<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This library implements a schematized DB on top of [RocksDB](https://rocksdb.org/). It makes
//! sure all data passed in and out are structured according to predefined schemas and prevents
//! access to raw keys and values. This library also enforces a set of Libra specific DB options,
//! like custom comparators and schema-to-column-family mapping.
//!
//! It requires that different kinds of key-value pairs be stored in separate column
//! families.  To use this library to store a kind of key-value pairs, the user needs to use the
//! [`define_schema!`] macro to define the schema name, the types of key and value, and name of the
//! column family.

#[macro_use]
pub mod schema;

use crate::schema::{KeyCodec, Schema, SeekKeyCodec, ValueCodec};
use failure::prelude::*;
use rocksdb::{
    rocksdb_options::ColumnFamilyDescriptor, CFHandle, DBOptions, Writable, WriteOptions,
};
use std::{collections::HashMap, iter::Iterator, marker::PhantomData, path::Path};

/// Type alias to `rocksdb::ColumnFamilyOptions`. See [`rocksdb doc`](https://github.com/pingcap/rust-rocksdb/blob/master/src/rocksdb_options.rs)
pub type ColumnFamilyOptions = rocksdb::ColumnFamilyOptions;
/// Type alias to `rocksdb::ReadOptions`. See [`rocksdb doc`](https://github.com/pingcap/rust-rocksdb/blob/master/src/rocksdb_options.rs)
pub type ReadOptions = rocksdb::ReadOptions;

/// Type alias to improve readability.
pub type ColumnFamilyName = &'static str;
/// Type alias to improve readability.
pub type ColumnFamilyOptionsMap = HashMap<ColumnFamilyName, ColumnFamilyOptions>;

/// Name for the `default` column family that's always open by RocksDB. We use it to store
/// [`LedgerInfo`](../types/ledger_info/struct.LedgerInfo.html).
pub const DEFAULT_CF_NAME: ColumnFamilyName = "default";

#[derive(Debug)]
enum WriteOp {
    Value(Vec<u8>),
    Deletion,
}

/// `SchemaBatch` holds a collection of updates that can be applied to a DB atomically. The updates
/// will be applied in the order in which they are added to the `SchemaBatch`.
#[derive(Debug, Default)]
pub struct SchemaBatch {
    rows: Vec<(ColumnFamilyName, Vec<u8> /* key */, WriteOp)>,
}

impl SchemaBatch {
    /// Creates an empty batch.
    pub fn new() -> Self {
        Self::default()
    }

    /// Adds an insert/update operation to the batch.
    pub fn put<S: Schema>(&mut self, key: &S::Key, value: &S::Value) -> Result<()> {
        let key = <S::Key as KeyCodec<S>>::encode_key(key)?;
        let value = <S::Value as ValueCodec<S>>::encode_value(value)?;
        self.rows
            .push((S::COLUMN_FAMILY_NAME, key, WriteOp::Value(value)));
        Ok(())
    }

    /// Adds a delete operation to the batch.
    pub fn delete<S: Schema>(&mut self, key: &S::Key) -> Result<()> {
        let key = <S::Key as KeyCodec<S>>::encode_key(key)?;
        self.rows
            .push((S::COLUMN_FAMILY_NAME, key, WriteOp::Deletion));
        Ok(())
    }
}

/// DB Iterator parameterized on [`Schema`] that seeks with [`Schema::Key`] and yields
/// [`Schema::Key`] and [`Schema::Value`]
pub struct SchemaIterator<'a, S> {
    db_iter: rocksdb::DBIterator<&'a rocksdb::DB>,
    phantom: PhantomData<S>,
}

impl<'a, S> SchemaIterator<'a, S>
where
    S: Schema,
{
    fn new(db_iter: rocksdb::DBIterator<&'a rocksdb::DB>) -> Self {
        SchemaIterator {
            db_iter,
            phantom: PhantomData,
        }
    }

    /// Seeks to the first key.
    pub fn seek_to_first(&mut self) -> bool {
        self.db_iter.seek(rocksdb::SeekKey::Start)
    }

    /// Seeks to the last key.
    pub fn seek_to_last(&mut self) -> bool {
        self.db_iter.seek(rocksdb::SeekKey::End)
    }

    /// Seeks to the first key whose binary representation is equal to or greater than that of the
    /// `seek_key`.
    pub fn seek<SK>(&mut self, seek_key: &SK) -> Result<bool>
    where
        SK: SeekKeyCodec<S>,
    {
        let key = <SK as SeekKeyCodec<S>>::encode_seek_key(seek_key)?;
        Ok(self.db_iter.seek(rocksdb::SeekKey::Key(&key)))
    }

    /// Seeks to the last key whose binary representation is less than or equal to that of the
    /// `seek_key`.
    ///
    /// See example in [`RocksDB doc`](https://github.com/facebook/rocksdb/wiki/SeekForPrev).
    pub fn seek_for_prev<SK>(&mut self, seek_key: &SK) -> Result<bool>
    where
        SK: SeekKeyCodec<S>,
    {
        let key = <SK as SeekKeyCodec<S>>::encode_seek_key(seek_key)?;
        Ok(self.db_iter.seek_for_prev(rocksdb::SeekKey::Key(&key)))
    }
}

impl<'a, S> Iterator for SchemaIterator<'a, S>
where
    S: Schema,
{
    type Item = Result<(S::Key, S::Value)>;

    fn next(&mut self) -> Option<Self::Item> {
        self.db_iter.kv().map(|(raw_key, raw_value)| {
            self.db_iter.next();
            Ok((
                <S::Key as KeyCodec<S>>::decode_key(&raw_key)?,
                <S::Value as ValueCodec<S>>::decode_value(&raw_value)?,
            ))
        })
    }
}

/// Checks underlying Rocksdb instance existence by checking `CURRENT` file existence, the same way
/// Rocksdb adopts to detect db existence.
fn db_exists(path: &Path) -> bool {
    let rocksdb_current_file = path.join("CURRENT");
    rocksdb_current_file.is_file()
}

/// All the RocksDB methods return `std::result::Result<T, String>`. Since our methods return
/// `failure::Result<T>`, manual conversion is needed.
fn convert_rocksdb_err(msg: String) -> failure::Error {
    format_err!("RocksDB internal error: {}.", msg)
}

/// This DB is a schematized RocksDB wrapper where all data passed in and out are typed according to
/// [`Schema`]s.
#[derive(Debug)]
pub struct DB {
    inner: rocksdb::DB,
}

impl DB {
    /// Create db with all the column families provided if it doesn't exist at `path`; Otherwise,
    /// try to open it with all the column families.
    pub fn open<P: AsRef<Path>>(path: P, mut cf_opts_map: ColumnFamilyOptionsMap) -> Result<Self> {
        let mut db_opts = DBOptions::new();

        // If db exists, just open it with all cfs.
        if db_exists(path.as_ref()) {
            return DB::open_cf(db_opts, &path, cf_opts_map.into_iter().collect());
        }

        // If db doesn't exist, create a db first with all column families.
        db_opts.create_if_missing(true);

        // For now we set the max total WAL size to be 1G. This config can be useful when column
        // families are updated at non-uniform frequencies.
        db_opts.set_max_total_wal_size(1 << 30);

        let mut db = DB::open_cf(
            db_opts,
            path,
            vec![cf_opts_map
                .remove_entry(&DEFAULT_CF_NAME)
                .ok_or_else(|| format_err!("No \"default\" column family name found"))?],
        )?;
        cf_opts_map
            .into_iter()
            .map(|(cf_name, cf_opts)| db.create_cf((cf_name, cf_opts)))
            .collect::<Result<Vec<_>>>()?;
        Ok(db)
    }

    fn open_cf<'a, P, T>(opts: DBOptions, path: P, cfds: Vec<T>) -> Result<DB>
    where
        P: AsRef<Path>,
        T: Into<ColumnFamilyDescriptor<'a>>,
    {
        let inner = rocksdb::DB::open_cf(
            opts,
            path.as_ref().to_str().ok_or_else(|| {
                format_err!("Path {:?} can not be converted to string.", path.as_ref())
            })?,
            cfds,
        )
        .map_err(convert_rocksdb_err)?;

        Ok(DB { inner })
    }

    fn create_cf<'a, T>(&mut self, cfd: T) -> Result<()>
    where
        T: Into<ColumnFamilyDescriptor<'a>>,
    {
        let _cf_handle = self.inner.create_cf(cfd).map_err(convert_rocksdb_err)?;
        Ok(())
    }

    /// Reads single record by key.
    pub fn get<S: Schema>(&self, schema_key: &S::Key) -> Result<Option<S::Value>> {
        let k = <S::Key as KeyCodec<S>>::encode_key(&schema_key)?;
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;

        self.inner
            .get_cf(cf_handle, &k)
            .map_err(convert_rocksdb_err)?
            .map(|raw_value| <S::Value as ValueCodec<S>>::decode_value(&raw_value))
            .transpose()
    }

    /// Writes single record.
    pub fn put<S: Schema>(&self, key: &S::Key, value: &S::Value) -> Result<()> {
        let k = <S::Key as KeyCodec<S>>::encode_key(&key)?;
        let v = <S::Value as ValueCodec<S>>::encode_value(&value)?;
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;

        self.inner
            .put_cf_opt(cf_handle, &k, &v, &default_write_options())
            .map_err(convert_rocksdb_err)
    }

    /// Returns a [`SchemaIterator`] on a certain schema.
    pub fn iter<S: Schema>(&self, opts: ReadOptions) -> Result<SchemaIterator<S>> {
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;
        Ok(SchemaIterator::new(self.inner.iter_cf_opt(cf_handle, opts)))
    }

    /// Writes a group of records wrapped in a [`SchemaBatch`].
    pub fn write_schemas(&self, batch: SchemaBatch) -> Result<()> {
        let db_batch = rocksdb::WriteBatch::new();
        for (cf_name, key, write_op) in &batch.rows {
            let cf_handle = self.get_cf_handle(cf_name)?;
            match write_op {
                WriteOp::Value(value) => db_batch.put_cf(cf_handle, &key, &value),
                WriteOp::Deletion => db_batch.delete_cf(cf_handle, &key),
            }
            .map_err(convert_rocksdb_err)?;
        }

        self.inner
            .write_opt(&db_batch, &default_write_options())
            .map_err(convert_rocksdb_err)
    }

    fn get_cf_handle(&self, cf_name: ColumnFamilyName) -> Result<&CFHandle> {
        self.inner.cf_handle(cf_name).ok_or_else(|| {
            format_err!(
                "DB::cf_handle not found for column family name: {}",
                cf_name
            )
        })
    }
}

/// For now we always use synchronous writes. This makes sure that once the operation returns
/// `Ok(())` the data is persisted even if the machine crashes. In the future we might consider
/// selectively turning this off for some non-critical writes to improve performance.
fn default_write_options() -> WriteOptions {
    let mut opts = WriteOptions::new();
    opts.set_sync(true);
    opts
}
<commit_msg>[schemadb] set options before creating/opening<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This library implements a schematized DB on top of [RocksDB](https://rocksdb.org/). It makes
//! sure all data passed in and out are structured according to predefined schemas and prevents
//! access to raw keys and values. This library also enforces a set of Libra specific DB options,
//! like custom comparators and schema-to-column-family mapping.
//!
//! It requires that different kinds of key-value pairs be stored in separate column
//! families.  To use this library to store a kind of key-value pairs, the user needs to use the
//! [`define_schema!`] macro to define the schema name, the types of key and value, and name of the
//! column family.

#[macro_use]
pub mod schema;

use crate::schema::{KeyCodec, Schema, SeekKeyCodec, ValueCodec};
use failure::prelude::*;
use rocksdb::{
    rocksdb_options::ColumnFamilyDescriptor, CFHandle, DBOptions, Writable, WriteOptions,
};
use std::{collections::HashMap, iter::Iterator, marker::PhantomData, path::Path};

/// Type alias to `rocksdb::ColumnFamilyOptions`. See [`rocksdb doc`](https://github.com/pingcap/rust-rocksdb/blob/master/src/rocksdb_options.rs)
pub type ColumnFamilyOptions = rocksdb::ColumnFamilyOptions;
/// Type alias to `rocksdb::ReadOptions`. See [`rocksdb doc`](https://github.com/pingcap/rust-rocksdb/blob/master/src/rocksdb_options.rs)
pub type ReadOptions = rocksdb::ReadOptions;

/// Type alias to improve readability.
pub type ColumnFamilyName = &'static str;
/// Type alias to improve readability.
pub type ColumnFamilyOptionsMap = HashMap<ColumnFamilyName, ColumnFamilyOptions>;

/// Name for the `default` column family that's always open by RocksDB. We use it to store
/// [`LedgerInfo`](../types/ledger_info/struct.LedgerInfo.html).
pub const DEFAULT_CF_NAME: ColumnFamilyName = "default";

#[derive(Debug)]
enum WriteOp {
    Value(Vec<u8>),
    Deletion,
}

/// `SchemaBatch` holds a collection of updates that can be applied to a DB atomically. The updates
/// will be applied in the order in which they are added to the `SchemaBatch`.
#[derive(Debug, Default)]
pub struct SchemaBatch {
    rows: Vec<(ColumnFamilyName, Vec<u8> /* key */, WriteOp)>,
}

impl SchemaBatch {
    /// Creates an empty batch.
    pub fn new() -> Self {
        Self::default()
    }

    /// Adds an insert/update operation to the batch.
    pub fn put<S: Schema>(&mut self, key: &S::Key, value: &S::Value) -> Result<()> {
        let key = <S::Key as KeyCodec<S>>::encode_key(key)?;
        let value = <S::Value as ValueCodec<S>>::encode_value(value)?;
        self.rows
            .push((S::COLUMN_FAMILY_NAME, key, WriteOp::Value(value)));
        Ok(())
    }

    /// Adds a delete operation to the batch.
    pub fn delete<S: Schema>(&mut self, key: &S::Key) -> Result<()> {
        let key = <S::Key as KeyCodec<S>>::encode_key(key)?;
        self.rows
            .push((S::COLUMN_FAMILY_NAME, key, WriteOp::Deletion));
        Ok(())
    }
}

/// DB Iterator parameterized on [`Schema`] that seeks with [`Schema::Key`] and yields
/// [`Schema::Key`] and [`Schema::Value`]
pub struct SchemaIterator<'a, S> {
    db_iter: rocksdb::DBIterator<&'a rocksdb::DB>,
    phantom: PhantomData<S>,
}

impl<'a, S> SchemaIterator<'a, S>
where
    S: Schema,
{
    fn new(db_iter: rocksdb::DBIterator<&'a rocksdb::DB>) -> Self {
        SchemaIterator {
            db_iter,
            phantom: PhantomData,
        }
    }

    /// Seeks to the first key.
    pub fn seek_to_first(&mut self) -> bool {
        self.db_iter.seek(rocksdb::SeekKey::Start)
    }

    /// Seeks to the last key.
    pub fn seek_to_last(&mut self) -> bool {
        self.db_iter.seek(rocksdb::SeekKey::End)
    }

    /// Seeks to the first key whose binary representation is equal to or greater than that of the
    /// `seek_key`.
    pub fn seek<SK>(&mut self, seek_key: &SK) -> Result<bool>
    where
        SK: SeekKeyCodec<S>,
    {
        let key = <SK as SeekKeyCodec<S>>::encode_seek_key(seek_key)?;
        Ok(self.db_iter.seek(rocksdb::SeekKey::Key(&key)))
    }

    /// Seeks to the last key whose binary representation is less than or equal to that of the
    /// `seek_key`.
    ///
    /// See example in [`RocksDB doc`](https://github.com/facebook/rocksdb/wiki/SeekForPrev).
    pub fn seek_for_prev<SK>(&mut self, seek_key: &SK) -> Result<bool>
    where
        SK: SeekKeyCodec<S>,
    {
        let key = <SK as SeekKeyCodec<S>>::encode_seek_key(seek_key)?;
        Ok(self.db_iter.seek_for_prev(rocksdb::SeekKey::Key(&key)))
    }
}

impl<'a, S> Iterator for SchemaIterator<'a, S>
where
    S: Schema,
{
    type Item = Result<(S::Key, S::Value)>;

    fn next(&mut self) -> Option<Self::Item> {
        self.db_iter.kv().map(|(raw_key, raw_value)| {
            self.db_iter.next();
            Ok((
                <S::Key as KeyCodec<S>>::decode_key(&raw_key)?,
                <S::Value as ValueCodec<S>>::decode_value(&raw_value)?,
            ))
        })
    }
}

/// Checks underlying Rocksdb instance existence by checking `CURRENT` file existence, the same way
/// Rocksdb adopts to detect db existence.
fn db_exists(path: &Path) -> bool {
    let rocksdb_current_file = path.join("CURRENT");
    rocksdb_current_file.is_file()
}

/// All the RocksDB methods return `std::result::Result<T, String>`. Since our methods return
/// `failure::Result<T>`, manual conversion is needed.
fn convert_rocksdb_err(msg: String) -> failure::Error {
    format_err!("RocksDB internal error: {}.", msg)
}

/// This DB is a schematized RocksDB wrapper where all data passed in and out are typed according to
/// [`Schema`]s.
#[derive(Debug)]
pub struct DB {
    inner: rocksdb::DB,
}

impl DB {
    /// Create db with all the column families provided if it doesn't exist at `path`; Otherwise,
    /// try to open it with all the column families.
    pub fn open<P: AsRef<Path>>(path: P, mut cf_opts_map: ColumnFamilyOptionsMap) -> Result<Self> {
        let mut db_opts = DBOptions::new();

        // For now we set the max total WAL size to be 1G. This config can be useful when column
        // families are updated at non-uniform frequencies.
        db_opts.set_max_total_wal_size(1 << 30);

        // If db exists, just open it with all cfs.
        if db_exists(path.as_ref()) {
            return DB::open_cf(db_opts, &path, cf_opts_map.into_iter().collect());
        }

        // If db doesn't exist, create a db first with all column families.
        db_opts.create_if_missing(true);

        let mut db = DB::open_cf(
            db_opts,
            path,
            vec![cf_opts_map
                .remove_entry(&DEFAULT_CF_NAME)
                .ok_or_else(|| format_err!("No \"default\" column family name found"))?],
        )?;
        cf_opts_map
            .into_iter()
            .map(|(cf_name, cf_opts)| db.create_cf((cf_name, cf_opts)))
            .collect::<Result<Vec<_>>>()?;
        Ok(db)
    }

    fn open_cf<'a, P, T>(opts: DBOptions, path: P, cfds: Vec<T>) -> Result<DB>
    where
        P: AsRef<Path>,
        T: Into<ColumnFamilyDescriptor<'a>>,
    {
        let inner = rocksdb::DB::open_cf(
            opts,
            path.as_ref().to_str().ok_or_else(|| {
                format_err!("Path {:?} can not be converted to string.", path.as_ref())
            })?,
            cfds,
        )
        .map_err(convert_rocksdb_err)?;

        Ok(DB { inner })
    }

    fn create_cf<'a, T>(&mut self, cfd: T) -> Result<()>
    where
        T: Into<ColumnFamilyDescriptor<'a>>,
    {
        let _cf_handle = self.inner.create_cf(cfd).map_err(convert_rocksdb_err)?;
        Ok(())
    }

    /// Reads single record by key.
    pub fn get<S: Schema>(&self, schema_key: &S::Key) -> Result<Option<S::Value>> {
        let k = <S::Key as KeyCodec<S>>::encode_key(&schema_key)?;
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;

        self.inner
            .get_cf(cf_handle, &k)
            .map_err(convert_rocksdb_err)?
            .map(|raw_value| <S::Value as ValueCodec<S>>::decode_value(&raw_value))
            .transpose()
    }

    /// Writes single record.
    pub fn put<S: Schema>(&self, key: &S::Key, value: &S::Value) -> Result<()> {
        let k = <S::Key as KeyCodec<S>>::encode_key(&key)?;
        let v = <S::Value as ValueCodec<S>>::encode_value(&value)?;
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;

        self.inner
            .put_cf_opt(cf_handle, &k, &v, &default_write_options())
            .map_err(convert_rocksdb_err)
    }

    /// Returns a [`SchemaIterator`] on a certain schema.
    pub fn iter<S: Schema>(&self, opts: ReadOptions) -> Result<SchemaIterator<S>> {
        let cf_handle = self.get_cf_handle(S::COLUMN_FAMILY_NAME)?;
        Ok(SchemaIterator::new(self.inner.iter_cf_opt(cf_handle, opts)))
    }

    /// Writes a group of records wrapped in a [`SchemaBatch`].
    pub fn write_schemas(&self, batch: SchemaBatch) -> Result<()> {
        let db_batch = rocksdb::WriteBatch::new();
        for (cf_name, key, write_op) in &batch.rows {
            let cf_handle = self.get_cf_handle(cf_name)?;
            match write_op {
                WriteOp::Value(value) => db_batch.put_cf(cf_handle, &key, &value),
                WriteOp::Deletion => db_batch.delete_cf(cf_handle, &key),
            }
            .map_err(convert_rocksdb_err)?;
        }

        self.inner
            .write_opt(&db_batch, &default_write_options())
            .map_err(convert_rocksdb_err)
    }

    fn get_cf_handle(&self, cf_name: ColumnFamilyName) -> Result<&CFHandle> {
        self.inner.cf_handle(cf_name).ok_or_else(|| {
            format_err!(
                "DB::cf_handle not found for column family name: {}",
                cf_name
            )
        })
    }
}

/// For now we always use synchronous writes. This makes sure that once the operation returns
/// `Ok(())` the data is persisted even if the machine crashes. In the future we might consider
/// selectively turning this off for some non-critical writes to improve performance.
fn default_write_options() -> WriteOptions {
    let mut opts = WriteOptions::new();
    opts.set_sync(true);
    opts
}
<|endoftext|>


<commit_before>use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use utils::{u8_from_hex_str, u8_to_hex_str};

/// Each of the BLS signature domains.
///
/// Spec v0.8.1
pub enum Domain {
    BeaconProposer,
    Randao,
    Attestation,
    Deposit,
    VoluntaryExit,
    Transfer,
}

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.8.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
    /*
     * Constants
     */
    #[serde(skip_serializing)] // skipped because Serde TOML has trouble with u64::max
    pub far_future_epoch: Epoch,
    pub base_rewards_per_epoch: u64,
    pub deposit_contract_tree_depth: u64,
    pub seconds_per_day: u64,

    /*
     * Misc
     */
    pub target_committee_size: usize,
    pub min_per_epoch_churn_limit: u64,
    pub churn_limit_quotient: u64,
    pub shuffle_round_count: u8,
    pub min_genesis_active_validator_count: u64,
    pub min_genesis_time: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_effective_balance: u64,
    pub ejection_balance: u64,
    pub effective_balance_increment: u64,

    /*
     * Initial Values
     */
    pub genesis_slot: Slot,
    #[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub milliseconds_per_slot: u64,
    pub min_attestation_inclusion_delay: u64,
    pub min_seed_lookahead: Epoch,
    pub activation_exit_delay: u64,
    pub min_validator_withdrawability_delay: Epoch,
    pub persistent_committee_period: u64,
    pub max_epochs_per_crosslink: u64,
    pub min_epochs_to_inactivity_penalty: u64,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_factor: u64,
    pub whistleblower_reward_quotient: u64,
    pub proposer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,
    pub min_slashing_penalty_quotient: u64,

    /*
     * Signature domains
     *
     * Fields should be private to prevent accessing a domain that hasn't been modified to suit
     * some `Fork`.
     *
     * Use `ChainSpec::get_domain(..)` to access these values.
     */
    domain_beacon_proposer: u32,
    domain_randao: u32,
    domain_attestation: u32,
    domain_deposit: u32,
    domain_voluntary_exit: u32,
    domain_transfer: u32,

    pub boot_nodes: Vec<String>,
    pub network_id: u8,
}

impl ChainSpec {
    /// Get the domain number that represents the fork meta and signature domain.
    ///
    /// Spec v0.8.1
    pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
        let domain_constant = match domain {
            Domain::BeaconProposer => self.domain_beacon_proposer,
            Domain::Randao => self.domain_randao,
            Domain::Attestation => self.domain_attestation,
            Domain::Deposit => self.domain_deposit,
            Domain::VoluntaryExit => self.domain_voluntary_exit,
            Domain::Transfer => self.domain_transfer,
        };

        let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
        bytes.append(&mut fork.get_fork_version(epoch).to_vec());

        let mut fork_and_domain = [0; 8];
        fork_and_domain.copy_from_slice(&bytes);

        u64::from_le_bytes(fork_and_domain)
    }

    /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
    ///
    /// Spec v0.8.1
    pub fn mainnet() -> Self {
        Self {
            /*
             * Constants
             */
            far_future_epoch: Epoch::new(u64::max_value()),
            base_rewards_per_epoch: 5,
            deposit_contract_tree_depth: 32,
            seconds_per_day: 86400,

            /*
             * Misc
             */
            target_committee_size: 128,
            min_per_epoch_churn_limit: 4,
            churn_limit_quotient: 65_536,
            shuffle_round_count: 90,
            min_genesis_active_validator_count: 65_536,
            min_genesis_time: 1_578_009_600, // Jan 3, 2020

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * u64::pow(10, 9),
            max_effective_balance: u64::pow(2, 5) * u64::pow(10, 9),
            ejection_balance: u64::pow(2, 4) * u64::pow(10, 9),
            effective_balance_increment: u64::pow(2, 0) * u64::pow(10, 9),

            /*
             * Initial Values
             */
            genesis_slot: Slot::new(0),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            milliseconds_per_slot: 6_000,
            min_attestation_inclusion_delay: 1,
            min_seed_lookahead: Epoch::new(1),
            activation_exit_delay: 4,
            min_validator_withdrawability_delay: Epoch::new(256),
            persistent_committee_period: 2_048,
            max_epochs_per_crosslink: 64,
            min_epochs_to_inactivity_penalty: 4,

            /*
             * Reward and penalty quotients
             */
            base_reward_factor: 64,
            whistleblower_reward_quotient: 512,
            proposer_reward_quotient: 8,
            inactivity_penalty_quotient: 33_554_432,
            min_slashing_penalty_quotient: 32,

            /*
             * Signature domains
             */
            domain_beacon_proposer: 0,
            domain_randao: 1,
            domain_attestation: 2,
            domain_deposit: 3,
            domain_voluntary_exit: 4,
            domain_transfer: 5,

            /*
             * Network specific
             */
            boot_nodes: vec![],
            network_id: 1, // mainnet network id
        }
    }

    /// Ethereum Foundation minimal spec, as defined here:
    ///
    /// https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/configs/constant_presets/minimal.yaml
    ///
    /// Spec v0.8.1
    pub fn minimal() -> Self {
        // Note: bootnodes to be updated when static nodes exist.
        let boot_nodes = vec![];

        Self {
            target_committee_size: 4,
            shuffle_round_count: 10,
            min_genesis_active_validator_count: 64,
            max_epochs_per_crosslink: 4,
            network_id: 2, // lighthouse testnet network id
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }

    /// Interop testing spec
    ///
    /// This allows us to customize a chain spec for interop testing.
    pub fn interop() -> Self {
        let boot_nodes = vec![];

        Self {
            milliseconds_per_slot: 12_000,
            target_committee_size: 4,
            shuffle_round_count: 10,
            network_id: 13,
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }
}

impl Default for ChainSpec {
    fn default() -> Self {
        Self::mainnet()
    }
}

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

    #[test]
    fn test_mainnet_spec_can_be_constructed() {
        let _ = ChainSpec::mainnet();
    }

    fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
        let fork = Fork::genesis(Epoch::new(0));
        let epoch = Epoch::new(0);

        let domain = spec.get_domain(epoch, domain_type, &fork);

        let mut expected = int_to_bytes4(raw_domain);
        expected.append(&mut fork.get_fork_version(epoch).to_vec());

        assert_eq!(int_to_bytes8(domain), expected);
    }

    #[test]
    fn test_get_domain() {
        let spec = ChainSpec::mainnet();

        test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
        test_domain(Domain::Randao, spec.domain_randao, &spec);
        test_domain(Domain::Attestation, spec.domain_attestation, &spec);
        test_domain(Domain::Deposit, spec.domain_deposit, &spec);
        test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
        test_domain(Domain::Transfer, spec.domain_transfer, &spec);
    }
}
<commit_msg>Updated ChainSpec serialization and added some comments about potentially missing components.<commit_after>use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use utils::{u8_from_hex_str, u8_to_hex_str};

/// Each of the BLS signature domains.
///
/// Spec v0.8.1
pub enum Domain {
    BeaconProposer,
    Randao,
    Attestation,
    Deposit,
    VoluntaryExit,
    Transfer,
}

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.8.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
    /*
     * Constants
     */
    pub far_future_epoch: Epoch,
    // The above may need to be skipped because Serde TOML has trouble with u64::max.
    // Use: #[serde(skip_serializing)]
    pub base_rewards_per_epoch: u64,
    pub deposit_contract_tree_depth: u64,
    pub seconds_per_day: u64,
    //TODO missing JUSTIFICATION_BITS_LENGTH and ENDIANNESS

    /*
     * Misc
     */
    pub target_committee_size: usize,
    pub min_per_epoch_churn_limit: u64,
    pub churn_limit_quotient: u64,
    pub shuffle_round_count: u8,
    pub min_genesis_active_validator_count: u64,
    pub min_genesis_time: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_effective_balance: u64,
    pub ejection_balance: u64,
    pub effective_balance_increment: u64,

    /*
     * Initial Values
     */
    pub genesis_slot: Slot,
    //TODO Missing genesis_epoch
    #[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub milliseconds_per_slot: u64,
    //TODO should we also have SECONDS_PER_SLOT?
    pub min_attestation_inclusion_delay: u64,
    pub min_seed_lookahead: Epoch,
    pub activation_exit_delay: u64,
    pub min_validator_withdrawability_delay: Epoch,
    pub persistent_committee_period: u64,
    pub max_epochs_per_crosslink: u64,
    pub min_epochs_to_inactivity_penalty: u64,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_factor: u64,
    pub whistleblower_reward_quotient: u64,
    pub proposer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,
    pub min_slashing_penalty_quotient: u64,

    /*
     * Signature domains
     *
     * Fields should be private to prevent accessing a domain that hasn't been modified to suit
     * some `Fork`.
     *
     * Use `ChainSpec::get_domain(..)` to access these values.
     */
    domain_beacon_proposer: u32,
    domain_randao: u32,
    domain_attestation: u32,
    domain_deposit: u32,
    domain_voluntary_exit: u32,
    domain_transfer: u32,

    pub boot_nodes: Vec<String>,
    pub network_id: u8,
}

impl ChainSpec {
    /// Get the domain number that represents the fork meta and signature domain.
    ///
    /// Spec v0.8.1
    pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
        let domain_constant = match domain {
            Domain::BeaconProposer => self.domain_beacon_proposer,
            Domain::Randao => self.domain_randao,
            Domain::Attestation => self.domain_attestation,
            Domain::Deposit => self.domain_deposit,
            Domain::VoluntaryExit => self.domain_voluntary_exit,
            Domain::Transfer => self.domain_transfer,
        };

        let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
        bytes.append(&mut fork.get_fork_version(epoch).to_vec());

        let mut fork_and_domain = [0; 8];
        fork_and_domain.copy_from_slice(&bytes);

        u64::from_le_bytes(fork_and_domain)
    }

    /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
    ///
    /// Spec v0.8.1
    pub fn mainnet() -> Self {
        Self {
            /*
             * Constants
             */
            far_future_epoch: Epoch::new(u64::max_value()),
            base_rewards_per_epoch: 5,
            deposit_contract_tree_depth: 32,
            seconds_per_day: 86400,

            /*
             * Misc
             */
            target_committee_size: 128,
            min_per_epoch_churn_limit: 4,
            churn_limit_quotient: 65_536,
            shuffle_round_count: 90,
            min_genesis_active_validator_count: 65_536,
            min_genesis_time: 1_578_009_600, // Jan 3, 2020

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * u64::pow(10, 9),
            max_effective_balance: u64::pow(2, 5) * u64::pow(10, 9),
            ejection_balance: u64::pow(2, 4) * u64::pow(10, 9),
            effective_balance_increment: u64::pow(2, 0) * u64::pow(10, 9),

            /*
             * Initial Values
             */
            genesis_slot: Slot::new(0),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            milliseconds_per_slot: 6_000,
            min_attestation_inclusion_delay: 1,
            min_seed_lookahead: Epoch::new(1),
            activation_exit_delay: 4,
            min_validator_withdrawability_delay: Epoch::new(256),
            persistent_committee_period: 2_048,
            max_epochs_per_crosslink: 64,
            min_epochs_to_inactivity_penalty: 4,

            /*
             * Reward and penalty quotients
             */
            base_reward_factor: 64,
            whistleblower_reward_quotient: 512,
            proposer_reward_quotient: 8,
            inactivity_penalty_quotient: 33_554_432,
            min_slashing_penalty_quotient: 32,

            /*
             * Signature domains
             */
            domain_beacon_proposer: 0,
            domain_randao: 1,
            domain_attestation: 2,
            domain_deposit: 3,
            domain_voluntary_exit: 4,
            domain_transfer: 5,

            /*
             * Network specific
             */
            boot_nodes: vec![],
            network_id: 1, // mainnet network id
        }
    }

    /// Ethereum Foundation minimal spec, as defined here:
    ///
    /// https://github.com/ethereum/eth2.0-specs/blob/v0.8.1/configs/constant_presets/minimal.yaml
    ///
    /// Spec v0.8.1
    pub fn minimal() -> Self {
        // Note: bootnodes to be updated when static nodes exist.
        let boot_nodes = vec![];

        Self {
            target_committee_size: 4,
            shuffle_round_count: 10,
            min_genesis_active_validator_count: 64,
            max_epochs_per_crosslink: 4,
            network_id: 2, // lighthouse testnet network id
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }

    /// Interop testing spec
    ///
    /// This allows us to customize a chain spec for interop testing.
    pub fn interop() -> Self {
        let boot_nodes = vec![];

        Self {
            milliseconds_per_slot: 12_000,
            target_committee_size: 4,
            shuffle_round_count: 10,
            network_id: 13,
            boot_nodes,
            ..ChainSpec::mainnet()
        }
    }
}

impl Default for ChainSpec {
    fn default() -> Self {
        Self::mainnet()
    }
}

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

    #[test]
    fn test_mainnet_spec_can_be_constructed() {
        let _ = ChainSpec::mainnet();
    }

    fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
        let fork = Fork::genesis(Epoch::new(0));
        let epoch = Epoch::new(0);

        let domain = spec.get_domain(epoch, domain_type, &fork);

        let mut expected = int_to_bytes4(raw_domain);
        expected.append(&mut fork.get_fork_version(epoch).to_vec());

        assert_eq!(int_to_bytes8(domain), expected);
    }

    #[test]
    fn test_get_domain() {
        let spec = ChainSpec::mainnet();

        test_domain(Domain::BeaconProposer, spec.domain_beacon_proposer, &spec);
        test_domain(Domain::Randao, spec.domain_randao, &spec);
        test_domain(Domain::Attestation, spec.domain_attestation, &spec);
        test_domain(Domain::Deposit, spec.domain_deposit, &spec);
        test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
        test_domain(Domain::Transfer, spec.domain_transfer, &spec);
    }
}
<|endoftext|>


<commit_before>/// Implements `Encode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Encode` for some type that implements a
/// `From` conversion into another type that already has `Encode` implemented.
#[macro_export]
macro_rules! impl_encode_via_from {
    ($impl_type: ty, $from_type: ty) => {
        impl ssz::Encode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Encode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Encode>::ssz_fixed_len()
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                let conv: $from_type = self.clone().into();

                conv.ssz_append(buf)
            }
        }
    };
}

/// Implements `Decode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Decode` for some type that implements a
/// `From` conversion into another type that already has `Decode` implemented.
#[macro_export]
macro_rules! impl_decode_via_from {
    ($impl_type: ty, $from_type: tt) => {
        impl ssz::Decode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Decode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Decode>::ssz_fixed_len()
            }

            fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
                $from_type::from_ssz_bytes(bytes).and_then(|dec| Ok(dec.into()))
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use crate as ssz;
    use self::ssz::{Decode, Encode};

    #[derive(PartialEq, Debug, Clone, Copy)]
    struct Wrapper(u64);

    impl From<u64> for Wrapper {
        fn from(x: u64) -> Wrapper {
            Wrapper(x)
        }
    }

    impl From<Wrapper> for u64 {
        fn from(x: Wrapper) -> u64 {
            x.0
        }
    }

    impl_encode_via_from!(Wrapper, u64);
    impl_decode_via_from!(Wrapper, u64);

    #[test]
    fn impl_encode_via_from() {
        let check_encode = |a: u64, b: Wrapper| assert_eq!(a.as_ssz_bytes(), b.as_ssz_bytes());

        check_encode(0, Wrapper(0));
        check_encode(1, Wrapper(1));
        check_encode(42, Wrapper(42));
    }

    #[test]
    fn impl_decode_via_from() {
        let check_decode = |bytes: Vec<u8>| {
            let a = u64::from_ssz_bytes(&bytes).unwrap();
            let b = Wrapper::from_ssz_bytes(&bytes).unwrap();

            assert_eq!(a, b.into())
        };

        check_decode(vec![0, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 2, 0, 0, 0]);
    }
}
<commit_msg>Fmt fix<commit_after>/// Implements `Encode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Encode` for some type that implements a
/// `From` conversion into another type that already has `Encode` implemented.
#[macro_export]
macro_rules! impl_encode_via_from {
    ($impl_type: ty, $from_type: ty) => {
        impl ssz::Encode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Encode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Encode>::ssz_fixed_len()
            }

            fn ssz_append(&self, buf: &mut Vec<u8>) {
                let conv: $from_type = self.clone().into();

                conv.ssz_append(buf)
            }
        }
    };
}

/// Implements `Decode` for `$impl_type` using an implementation of `From<$impl_type> for
/// $from_type`.
///
/// In effect, this allows for easy implementation of `Decode` for some type that implements a
/// `From` conversion into another type that already has `Decode` implemented.
#[macro_export]
macro_rules! impl_decode_via_from {
    ($impl_type: ty, $from_type: tt) => {
        impl ssz::Decode for $impl_type {
            fn is_ssz_fixed_len() -> bool {
                <$from_type as ssz::Decode>::is_ssz_fixed_len()
            }

            fn ssz_fixed_len() -> usize {
                <$from_type as ssz::Decode>::ssz_fixed_len()
            }

            fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
                $from_type::from_ssz_bytes(bytes).and_then(|dec| Ok(dec.into()))
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use self::ssz::{Decode, Encode};
    use crate as ssz;

    #[derive(PartialEq, Debug, Clone, Copy)]
    struct Wrapper(u64);

    impl From<u64> for Wrapper {
        fn from(x: u64) -> Wrapper {
            Wrapper(x)
        }
    }

    impl From<Wrapper> for u64 {
        fn from(x: Wrapper) -> u64 {
            x.0
        }
    }

    impl_encode_via_from!(Wrapper, u64);
    impl_decode_via_from!(Wrapper, u64);

    #[test]
    fn impl_encode_via_from() {
        let check_encode = |a: u64, b: Wrapper| assert_eq!(a.as_ssz_bytes(), b.as_ssz_bytes());

        check_encode(0, Wrapper(0));
        check_encode(1, Wrapper(1));
        check_encode(42, Wrapper(42));
    }

    #[test]
    fn impl_decode_via_from() {
        let check_decode = |bytes: Vec<u8>| {
            let a = u64::from_ssz_bytes(&bytes).unwrap();
            let b = Wrapper::from_ssz_bytes(&bytes).unwrap();

            assert_eq!(a, b.into())
        };

        check_decode(vec![0, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 0, 0, 0, 0]);
        check_decode(vec![1, 0, 0, 0, 2, 0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(interpolate_idents)]

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF, ACCESS_CONF};

new_module!(
   conf, b"mod_conf\0",
   config {
      directory {
         DirectoryConfig {
            dir_var: StringType
         },
         create_directory_config
      },
      server {
         ServerConfig {
            enabled: BoolType,
            string_var: StringType
         },
         create_server_config
      }, [
         (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"),
         (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string directive\0"),
         (TAKE1, b"DirVar\0", dir_var, ACCESS_CONF, b"Directory string directive\0")
      ]
   }
);

fn create_server_config<'a>(pool: &mut Pool) -> ServerConfig<'a> {
   let mut config = ServerConfig::new(pool).unwrap();

   config.set_enabled(false);

   config
}

fn create_directory_config<'a>(pool: &mut Pool, _: Option<&'a str>) -> DirectoryConfig<'a> {
   DirectoryConfig::new(pool).unwrap()
}

fn enabled_var(parms: &mut CmdParms, _: Option<DirectoryConfig>, on: bool) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_enabled(on);

   Ok(())
}

fn string_var<'a>(parms: &mut CmdParms, _: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_string_var(w);

   Ok(())
}

fn dir_var<'a>(_: &mut CmdParms, mconfig: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = mconfig.unwrap();

   config.set_dir_var(w);

   Ok(())
}

fn unwrap_str<'a>(wrapped: Result<&'a str, ()>) -> &'a str {
   wrapped.unwrap_or("--")
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let server_config = get_server_config(
      &mut try!(r.pool()),
      &try!(try!(r.server()).module_config())
   );

   r.set_content_type("text/plain; charset=utf-8");

   let enabled = try!(server_config.enabled());
   try!(r.write(format!("EnabledVar: {}\n", enabled)));

   let string_var = unwrap_str(server_config.string_var());
   try!(r.write(format!("StringVar: {}\n", string_var)));

   let dir_config = get_dir_config(
      &mut try!(r.pool()),
      &try!(r.per_dir_config())
   );

   let dir_var = unwrap_str(dir_config.dir_var());
   try!(r.write(format!("DirVar: {}\n", dir_var)));

   Ok(Status::OK)
}
<commit_msg>Renaming a function in mod_conf.<commit_after>#![feature(plugin)]
#![plugin(interpolate_idents)]

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, Pool, CmdParms, BoolType, StringType, RSRC_CONF, ACCESS_CONF};

new_module!(
   conf, b"mod_conf\0",
   config {
      directory {
         DirectoryConfig {
            dir_var: StringType
         },
         create_dir_config
      },
      server {
         ServerConfig {
            enabled: BoolType,
            string_var: StringType
         },
         create_server_config
      }, [
         (FLAG, b"EnabledVar\0", enabled_var, RSRC_CONF, b"Example flag\0"),
         (TAKE1, b"StringVar\0", string_var, RSRC_CONF, b"Example string directive\0"),
         (TAKE1, b"DirVar\0", dir_var, ACCESS_CONF, b"Directory string directive\0")
      ]
   }
);

fn create_server_config<'a>(pool: &mut Pool) -> ServerConfig<'a> {
   let mut config = ServerConfig::new(pool).unwrap();

   config.set_enabled(false);

   config
}

fn create_dir_config<'a>(pool: &mut Pool, _: Option<&'a str>) -> DirectoryConfig<'a> {
   DirectoryConfig::new(pool).unwrap()
}

fn enabled_var(parms: &mut CmdParms, _: Option<DirectoryConfig>, on: bool) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_enabled(on);

   Ok(())
}

fn string_var<'a>(parms: &mut CmdParms, _: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = get_server_config(
      &mut try!(parms.pool()),
      &try!(try!(parms.server()).module_config())
   );

   config.set_string_var(w);

   Ok(())
}

fn dir_var<'a>(_: &mut CmdParms, mconfig: Option<DirectoryConfig>, w: &'a str) -> Result<(), ()> {
   let mut config = mconfig.unwrap();

   config.set_dir_var(w);

   Ok(())
}

fn unwrap_str<'a>(wrapped: Result<&'a str, ()>) -> &'a str {
   wrapped.unwrap_or("--")
}

fn conf_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "conf" {
      return Ok(Status::DECLINED)
   }

   let server_config = get_server_config(
      &mut try!(r.pool()),
      &try!(try!(r.server()).module_config())
   );

   r.set_content_type("text/plain; charset=utf-8");

   let enabled = try!(server_config.enabled());
   try!(r.write(format!("EnabledVar: {}\n", enabled)));

   let string_var = unwrap_str(server_config.string_var());
   try!(r.write(format!("StringVar: {}\n", string_var)));

   let dir_config = get_dir_config(
      &mut try!(r.pool()),
      &try!(r.per_dir_config())
   );

   let dir_var = unwrap_str(dir_config.dir_var());
   try!(r.write(format!("DirVar: {}\n", dir_var)));

   Ok(Status::OK)
}
<|endoftext|>


<commit_before>use std::io::{Error, ErrorKind};
use std::result::Result;

fn range_vec<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<Vec<T>, Error>
where
    T: Copy + Clone,
{
    if i >= nl.len() {
        return Err(Error::new(
            ErrorKind::Other,
            "first index larger than length",
        ));
    }

    let mut jj;

    if j > nl.len() {
        jj = nl.len() - 1;
    } else {
        jj = j - 1;
    }

    let mut ind = 0;
    let mut result: Vec<T> = vec![];

    for this in nl {
        if ind >= i && ind <= jj {
            result.push(*this);
        }
        ind += 1;
    }

    Result::Ok(result)
}

fn main() {
    let a = vec![1, 2, 3, 4, 5, 6];
    println!("{:?}", range_vec(&a, 0, 1));
    println!("{:?}", range_vec(&a, 2, 6));
    println!("{:?}", range_vec(&a, 6, 6));
    println!("{:?}", range_vec(&a, 5, 6));
}
<commit_msg>learn how to resolve Associated types vs type parameter conflict<commit_after>use std::io::{Error, ErrorKind};
use std::ops::Add;
use std::result::Result;

fn range_vec<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<Vec<T>, Error>
where
    T: Copy + Clone,
{
    if i >= nl.len() {
        return Err(Error::new(
            ErrorKind::Other,
            "first index larger than length",
        ));
    }

    let mut jj;

    if j > nl.len() {
        jj = nl.len() - 1;
    } else {
        jj = j - 1;
    }

    let mut ind = 0;
    let mut result: Vec<T> = vec![];

    for this in nl {
        if ind >= i && ind <= jj {
            result.push(*this);
        }
        ind += 1;
    }

    Result::Ok(result)
}

fn sum_vec<T>(nl: &Vec<T>) -> T
where
    T: Add<Output = T> + Copy + Clone,
{
    let mut result: T = *nl.first().unwrap();
    if let Some((_, last)) = nl.split_first() {
        for this in last {
            result = result + (*this);
        }
    }
    result
}

/*
fn sum_range<T>(nl: &Vec<T>, i: usize, j: usize) -> Result<T, Error>
where
    T: Add + Copy + Clone,
{

}*/

fn main() {
    let a = vec![1, 2, 3, 4, 5, 6];
    println!("{:?}", range_vec(&a, 0, 1));
    println!("{:?}", range_vec(&a, 2, 6));
    println!("{:?}", range_vec(&a, 6, 6));
    println!("{:?}", range_vec(&a, 5, 6));
    //main thread cannot use `?`
    //println!("{:?}", range_vec(&a, 2, 6)?);

    println!("{:?}", sum_vec(&a));
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::{fs, io};
use std::borrow::Cow;
use thiserror::Error;

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

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

#[derive(Debug, Clone, PartialEq)]
pub enum Regression {
    Median {
        threshold: f64,
        difference: f64,
        baseline: f64,
        dev: f64,
    },
    StandardDeviation {
        threshold: f64,
        difference: f64,
        baseline: f64,
        dev: f64,
    },
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    version: String,
    run: String,
    measurement: Measurement,
}

#[derive(Error, Debug)]
pub enum TestError {
    #[error("BadJSONErr: JSON in file cannot be deserialized as expected.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadJSONErr(PathBuf, Option<serde_json::Error>),
    #[error("ReadErr: The file cannot be read.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    ReadErr(PathBuf, Option<io::Error>),
    #[error("MissingFilenameErr: The path provided does not specify a file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    MissingFilenameErr(PathBuf),
    #[error("FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    FilenameNotUnicodeErr(PathBuf),
    #[error("BadFileContentsErr: Check that the file exists and is readable.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadFileContentsErr(PathBuf, Option<io::Error>),
    #[error("NoResultsErr: The results directory has no json files in it.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    NoResultsErr(PathBuf),
    #[error("OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.\nFile Count: {}\nFilepath: {}", .0, .1.to_string_lossy().into_owned())]
    OddResultsCountErr(usize, PathBuf),
    #[error("BadGroupSizeErr: Expected two results per group, one for each branch-project pair.\nCount: {}\nGroup: {:?}", .0, .1.into_iter().map(|group| (&group.version[..], &group.run[..])).collect::<Vec<(&str, &str)>>())]
    BadGroupSizeErr(usize, Vec<MeasurementGroup>),
}

fn regression(baseline: &Measurement, dev: &Measurement) -> Vec<Regression> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    let mut regressions = vec![];

    if median_difference > median_threshold {
        regressions.push(
            Regression::Median {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median.clone(),
                dev: dev.median.clone(),
            }
        )
    };

    if stddev_difference > stddev_threshold {
        regressions.push(
            Regression::StandardDeviation {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev.clone(),
                dev: dev.stddev.clone(),
            }
        )
    };

    regressions
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, TestError> {
    let result_files = fs::read_dir(results_directory)
        .or_else(|e| Err(TestError::ReadErr(results_directory.to_path_buf(), Some(e))))?;

    result_files
        .into_iter()
        .map(|f| f.unwrap().path())
        .filter(|filename| {
            filename
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|filename| {
            fs::read_to_string(&filename)
                .or_else(|e| Err(TestError::BadFileContentsErr(filename.clone(), Some(e))))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(TestError::BadJSONErr(filename.clone(), Some(e))))
                })
                .map(|m| (filename, m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(PathBuf, Measurement)],
) -> Result<Vec<Regression>, TestError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .into_iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| TestError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| TestError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: m.clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, TestError>>()?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let x: Vec<Regression> = sorted_measurement_groups
        .into_iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, group)| {
            let g: Vec<MeasurementGroup> = group.collect();
            match g.len() {
                2 => regression(&g[0].measurement, &g[1].measurement).into_iter().map(Ok).collect(),
                i => vec![Err(TestError::BadGroupSizeErr(i, g))],
            }
        })
        .flatten()
        .collect::<Result<Vec<Regression>, TestError>>()?;

    Ok(x)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Regression>, TestError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| {
        // exit early with an Err if there are no results to process
        match v.len() {
            0 => Err(TestError::NoResultsErr(results_directory.clone())),
            i if i % 2 == 1 => Err(TestError::OddResultsCountErr(i, results_directory.clone())),
            _ => Ok(()),
        }?;

        let v_next: Vec<(PathBuf, Measurement)> = v
            .into_iter()
            // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
            .map(|(p, ms)| (p, ms.results[0].clone()))
            .collect();

        println!("checking regressions with the following measurements:");
        for (path, _) in &v_next {
            // TODO this printed nothing. What's the size of this vector?
            println!("{}", path.file_name().map(|x| x.to_string_lossy()).unwrap_or(Cow::from("unknown file")))
        }

        calculate_regressions(&v_next)
    })
}

pub fn exit_properly(regressions: Vec<Regression>) {
    match regressions[..] {
        [] => println!("congrats! no regressions"),
        _ => {
            for r in regressions {
                println!("{:#?}", r);
            }
            println!("the above regressions were found.");
            exit(1)
        }
    }
}

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

    #[test]
    fn test_error_messages() {
        let pairs = vec![
            (
                TestError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                TestError::ReadErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"ReadErr: The file cannot be read.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                TestError::MissingFilenameErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"MissingFilenameErr: The path provided does not specify a file.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::FilenameNotUnicodeErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::BadFileContentsErr(Path::new("dummy/path/filenotexist.json").to_path_buf(), None),
                r#"BadFileContentsErr: Check that the file exists and is readable.
Filepath: dummy/path/filenotexist.json
Originating Exception:None"#
            ),
            (
                TestError::NoResultsErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"NoResultsErr: The results directory has no json files in it.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::OddResultsCountErr(3, Path::new("dummy/path/no_file/").to_path_buf()),
                r#"OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.
File Count: 3
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::BadGroupSizeErr(1, vec![MeasurementGroup {
                    version: "dev".to_owned(),
                    run: "some command".to_owned(),
                    measurement: Measurement {
                        command: "some command".to_owned(),
                        mean: 1.0,
                        stddev: 1.0,
                        median: 1.0,
                        user: 1.0,
                        system: 1.0,
                        min: 1.0,
                        max: 1.0,
                        times: vec![1.0, 1.1, 0.9, 1.0, 1.1, 0.9, 1.1],
                    }
                }]),
                r#"BadGroupSizeErr: Expected two results per group, one for each branch-project pair.
Count: 1
Group: [("dev", "some command")]"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

}
<commit_msg>return all calculations not just regressions<commit_after>use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::{fs, io};
use std::borrow::Cow;
use thiserror::Error;

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

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

#[derive(Debug, Clone, PartialEq)]
struct Data {
    threshold: f64,
    difference: f64,
    baseline: f64,
    dev: f64,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Calculation {
    metric: String,
    regression: bool,
    data: Data,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    version: String,
    run: String,
    measurement: Measurement,
}

#[derive(Error, Debug)]
pub enum TestError {
    #[error("BadJSONErr: JSON in file cannot be deserialized as expected.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadJSONErr(PathBuf, Option<serde_json::Error>),
    #[error("ReadErr: The file cannot be read.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    ReadErr(PathBuf, Option<io::Error>),
    #[error("MissingFilenameErr: The path provided does not specify a file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    MissingFilenameErr(PathBuf),
    #[error("FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    FilenameNotUnicodeErr(PathBuf),
    #[error("BadFileContentsErr: Check that the file exists and is readable.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadFileContentsErr(PathBuf, Option<io::Error>),
    #[error("NoResultsErr: The results directory has no json files in it.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    NoResultsErr(PathBuf),
    #[error("OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.\nFile Count: {}\nFilepath: {}", .0, .1.to_string_lossy().into_owned())]
    OddResultsCountErr(usize, PathBuf),
    #[error("BadGroupSizeErr: Expected two results per group, one for each branch-project pair.\nCount: {}\nGroup: {:?}", .0, .1.into_iter().map(|group| (&group.version[..], &group.run[..])).collect::<Vec<(&str, &str)>>())]
    BadGroupSizeErr(usize, Vec<MeasurementGroup>),
}

fn calculate(metric: &str, baseline: &Measurement, dev: &Measurement) -> Vec<Calculation> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    vec![
        Calculation {
            metric: ["median", metric].join("_"),
            regression: median_difference > median_threshold,
            data: Data {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median.clone(),
                dev: dev.median.clone(),
            }
        },
        Calculation {
            metric: ["stddev", metric].join("_"),
            regression: stddev_difference > stddev_threshold,
            data: Data {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev.clone(),
                dev: dev.stddev.clone(),
            }
        },
    ]
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, TestError> {
    let result_files = fs::read_dir(results_directory)
        .or_else(|e| Err(TestError::ReadErr(results_directory.to_path_buf(), Some(e))))?;

    result_files
        .into_iter()
        .map(|f| f.unwrap().path())
        .filter(|filename| {
            filename
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|filename| {
            fs::read_to_string(&filename)
                .or_else(|e| Err(TestError::BadFileContentsErr(filename.clone(), Some(e))))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(TestError::BadJSONErr(filename.clone(), Some(e))))
                })
                .map(|m| (filename, m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(PathBuf, Measurement)],
) -> Result<Vec<Calculation>, TestError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .into_iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| TestError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| TestError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: m.clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, TestError>>()?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let x: Vec<Calculation> = sorted_measurement_groups
        .into_iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, group)| {
            let g: Vec<MeasurementGroup> = group.collect();
            match g.len() {
                2 => calculate(&g[0].run, &g[0].measurement, &g[1].measurement).into_iter().map(Ok).collect(),
                i => vec![Err(TestError::BadGroupSizeErr(i, g))],
            }
        })
        .flatten()
        .collect::<Result<Vec<Calculation>, TestError>>()?;

    Ok(x)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Calculation>, TestError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| {
        // exit early with an Err if there are no results to process
        match v.len() {
            0 => Err(TestError::NoResultsErr(results_directory.clone())),
            i if i % 2 == 1 => Err(TestError::OddResultsCountErr(i, results_directory.clone())),
            _ => Ok(()),
        }?;

        let v_next: Vec<(PathBuf, Measurement)> = v
            .into_iter()
            // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
            .map(|(p, ms)| (p, ms.results[0].clone()))
            .collect();

        println!("checking regressions with the following measurements:");
        for (path, _) in &v_next {
            // TODO this printed nothing. What's the size of this vector?
            println!("{}", path.file_name().map(|x| x.to_string_lossy()).unwrap_or(Cow::from("unknown file")))
        }

        calculate_regressions(&v_next)
    })
}

pub fn exit_properly(calculations: Vec<Calculation>) {
    let regressions = calculations.into_iter().filter(|c| c.regression).collect::<Vec<Calculation>>();
    match regressions[..] {
        [] => println!("congrats! no regressions"),
        _ => {
            for r in regressions {
                println!("{:#?}", r);
            }
            println!("");
            println!("the above regressions were found.");
            exit(1)
        }
    }
}

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

    #[test]
    fn test_error_messages() {
        let pairs = vec![
            (
                TestError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                TestError::ReadErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"ReadErr: The file cannot be read.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                TestError::MissingFilenameErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"MissingFilenameErr: The path provided does not specify a file.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::FilenameNotUnicodeErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::BadFileContentsErr(Path::new("dummy/path/filenotexist.json").to_path_buf(), None),
                r#"BadFileContentsErr: Check that the file exists and is readable.
Filepath: dummy/path/filenotexist.json
Originating Exception:None"#
            ),
            (
                TestError::NoResultsErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"NoResultsErr: The results directory has no json files in it.
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::OddResultsCountErr(3, Path::new("dummy/path/no_file/").to_path_buf()),
                r#"OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.
File Count: 3
Filepath: dummy/path/no_file/"#
            ),
            (
                TestError::BadGroupSizeErr(1, vec![MeasurementGroup {
                    version: "dev".to_owned(),
                    run: "some command".to_owned(),
                    measurement: Measurement {
                        command: "some command".to_owned(),
                        mean: 1.0,
                        stddev: 1.0,
                        median: 1.0,
                        user: 1.0,
                        system: 1.0,
                        min: 1.0,
                        max: 1.0,
                        times: vec![1.0, 1.1, 0.9, 1.0, 1.1, 0.9, 1.1],
                    }
                }]),
                r#"BadGroupSizeErr: Expected two results per group, one for each branch-project pair.
Count: 1
Group: [("dev", "some command")]"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

}
<|endoftext|>


<commit_before>extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;

use std::collections::HashMap;

use proc_macro::TokenStream;
use proc_macro2::Ident;
use syn::{ItemFn, Stmt, UseTree, ItemUse, Item, Block, Expr,
          parse::{self, Parse, ParseStream},
          punctuated::Punctuated,
          fold::Fold};

/// Parses a list of variable names separated by commas
///
///     a, b, c
///
/// This is how the compiler passes in arguments to our attribute -- it is
/// everything inside the delimiters after the attribute name.
///
///     #[wlroots_dehandle(a, b, c)]
///
struct Args {
    vars: HashMap<Ident, bool>
}

impl Parse for Args {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
        Ok(Args {
            vars: vars.into_iter().map(|k| (k, false)).collect(),
        })
    }
}

impl Fold for Args {
    fn fold_block(&mut self, block: Block) -> Block {
        build_block(block.stmts.iter(), self)
    }
}

impl Args {
    fn is_handle(&mut self, name: Ident) -> bool {
        if let Some(seen) = self.vars.get_mut(&name) {
            *seen = true;
            true
        } else {
            false
        }
    }
}

/// Attribute to automatically call the `run` method on handles with the
/// remaining block of code.
///
/// The name of the variable you want to use as the upgraded handle should be
/// provided as an argument to the attribute. It does not need to be the same
/// as the handle variable.
///
/// The syntax in the code should be `use $handle as $upgraded_handle`.
/// E.g the variable in the code that stores the handle should go on the
/// **left** and the variable you used in the attribute declaration should
/// go on the **right**.
///
/// # Example
///
/// ```
/// impl InputManagerHandler for InputManager {
///     #[wlroots_dehandle(compositor, keyboard, seat)]
///     fn keyboard_added(&mut self,
///                       compositor_handle: CompositorHandle,
///                       keyboard: KeyboardHandle)
///                       -> Option<Box<Keyboard Handler>> {
///         use compositor_handle as compositor;
///         let keyboard = keyboard;
///         use compositor as compositor;
///         use keyboard as keyboard;
///         let server: &mut ::Server = compositor.into();
///         server.keyboards.push(keyboard.weak_reference());
///         // Now that we have at least one keyboard, update the seat capabilities.
///         let server_seat = &server.seat.seat;
///         use server_seat as seat;
///         let mut capabilities = seat.capabilities();
///         capabilities.insert(Capability::Keyboard);
///         seat.set_capabilities(capabilities);
///         seat.set_keyboard(keyboard.input_device());
///         Some(Box::new(::Keyboard))
///     }
/// }
/// ```
#[proc_macro_attribute]
pub fn wlroots_dehandle(args: TokenStream, input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as ItemFn);
    let mut args = parse_macro_input!(args as Args);
    if args.vars.len() == 0 {
        panic!("wlroots_dehandle requires at least one argument")
    }
    let output = args.fold_item_fn(input);
    for (arg, seen) in args.vars {
        if !seen {
            panic!(format!("Must use all declared handles, didn't use `{}`",
                           arg))
        }
    }
    TokenStream::from(quote!(#output))
}

fn build_block(mut input: std::slice::Iter<Stmt>, args: &mut Args) -> Block {
    let mut output = vec![];
    let mut inner = None;
    while let Some(stmt) = input.next().cloned() {
        use {Item::Use, UseTree::Rename};
        match stmt.clone() {
            Stmt::Item(Use(ItemUse { tree: Rename(use_stmt), ..})) => {
                if args.is_handle(use_stmt.rename.clone()) {
                    inner = Some((use_stmt.ident, use_stmt.rename));
                    break
                }
                output.push(stmt)
            },
            // Recurse into function body
            Stmt::Item(Item::Fn(mut function)) => {
                let inner_block = function.block.clone();
                *function.block = build_block(inner_block.stmts.iter(), args);
                output.push(Stmt::Item(Item::Fn(function)))
            },
            // Recurse into let call
            Stmt::Local(mut local) => {
                if let Some((_, body)) = local.init.clone() {
                    let body = build_block_expr(*body.clone(), args);
                    let body = parse_quote!(#body);
                    local.init.as_mut().unwrap().1 = body;
                    output.push(Stmt::Local(local))
                }
            },
            Stmt::Expr(expr) => {
                let body = build_block_expr(expr, args);
                output.push(parse_quote!({#body}))
            }
            Stmt::Semi(expr, _) => {
                let body = build_block_expr(expr, args);
                output.push(parse_quote!({#body;}))
            }
            _ => output.push(stmt)
        }
    }
    if let Some((handle, dehandle)) = inner {
        let inner_block = build_block(input, args);
        let handle_call = parse_quote!(
            {(#handle).run(|#dehandle|{
                #inner_block
            }).expect(concat!("Could not upgrade handle ",
                              stringify!(#handle), " to ",
                              stringify!(#dehandle)))}
        );
        output.push(handle_call);
    }
    parse_quote!({#(#output)*})
}

/// Tries to build a block from the expression.
fn build_block_expr(expr: Expr, args: &mut Args) -> Expr {
    match expr {
        Expr::Block(block) => {
            let block = build_block(block.block.stmts.iter(), args);
            parse_quote!(#block)
        }
        Expr::Let(mut let_expr) => {
            *let_expr.expr = build_block_expr(*let_expr.expr.clone(), args);
            Expr::Let(let_expr)
        },
        Expr::If(mut if_expr) => {
            let then_branch = if_expr.then_branch.clone();
            let then_branch = build_block_expr(parse_quote!(#then_branch), args);
            if_expr.then_branch = parse_quote!(#then_branch);
            if_expr.else_branch = match if_expr.else_branch.clone() {
                None => if_expr.else_branch,
                Some((token, else_branch)) => {
                    Some((token, Box::new( build_block_expr(*else_branch, args))))
                }
            };
            Expr::If(if_expr)
        },
        Expr::While(mut while_expr) => {
            let body = while_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            while_expr.body = parse_quote!(#body);
            Expr::While(while_expr)
        },
        Expr::ForLoop(mut for_expr) => {
            let body = for_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            for_expr.body = parse_quote!(#body);
            Expr::ForLoop(for_expr)
        },
        Expr::Loop(mut loop_expr) => {
            let body = loop_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            loop_expr.body = parse_quote!(#body);
            Expr::Loop(loop_expr)
        },
        Expr::Match(mut match_expr) => {
            for arm in &mut match_expr.arms {
                *arm.body = build_block_expr(*arm.body.clone(), args)
            }
            Expr::Match(match_expr)
        },
        Expr::Struct(mut struct_expr) => {
            for field in &mut struct_expr.fields {
                field.expr = build_block_expr(field.expr.clone(), args);
            }
            Expr::Struct(struct_expr)
        },
        Expr::Call(mut call_expr) => {
            for arg in &mut call_expr.args {
                *arg = build_block_expr(arg.clone(), args);
            }
            Expr::Call(call_expr)
        },
        Expr::MethodCall(mut call_expr) => {
            for arg in &mut call_expr.args {
                *arg = build_block_expr(arg.clone(), args);
            }
            Expr::MethodCall(call_expr)
        },
        Expr::Closure(mut closure_expr) => {
            *closure_expr.body = build_block_expr(*closure_expr.body.clone(),
                                                  args);
            Expr::Closure(closure_expr)
        },
        Expr::Unsafe(mut unsafe_expr) => {
            unsafe_expr.block = build_block(unsafe_expr.block.stmts.iter(),
                                            args);
            Expr::Unsafe(unsafe_expr)
        },
        Expr::Assign(mut assign_expr) => {
            *assign_expr.right = build_block_expr(*assign_expr.right.clone(),
                                                  args);
            Expr::Assign(assign_expr)
        },
        Expr::AssignOp(mut assign_expr) => {
            *assign_expr.right = build_block_expr(*assign_expr.right.clone(),
                                                  args);
            Expr::AssignOp(assign_expr)
        },
        Expr::Break(mut break_expr) => {
            match break_expr.expr {
                None => {},
                Some(ref mut expr) => {
                    **expr = build_block_expr(*expr.clone(), args);
                }
            }
            Expr::Break(break_expr)
        },
        Expr::Return(mut return_expr) => {
            match return_expr.expr {
                None => {},
                Some(ref mut expr) => {
                    **expr = build_block_expr(*expr.clone(), args);
                }
            }
            Expr::Return(return_expr)
        },
        Expr::Reference(mut reference_expr) => {
            *reference_expr.expr = build_block_expr(*reference_expr.expr.clone(),
                                                    args);
            Expr::Reference(reference_expr)
        },
        Expr::Paren(mut paren_expr) => {
            *paren_expr.expr = build_block_expr(*paren_expr.expr.clone(), args);
            Expr::Paren(paren_expr)
        },
        Expr::Unary(mut unary_expr) => {
            *unary_expr.expr = build_block_expr(*unary_expr.expr.clone(), args);
            Expr::Unary(unary_expr)
        },
        Expr::Binary(mut binary_expr) => {
            *binary_expr.left = build_block_expr(*binary_expr.left.clone(), args);
            *binary_expr.right = build_block_expr(*binary_expr.right.clone(), args);
            Expr::Binary(binary_expr)
        },
        v => {
            v
        }
    }
}
<commit_msg>Updated documentation example<commit_after>extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;

use std::collections::HashMap;

use proc_macro::TokenStream;
use proc_macro2::Ident;
use syn::{ItemFn, Stmt, UseTree, ItemUse, Item, Block, Expr,
          parse::{self, Parse, ParseStream},
          punctuated::Punctuated,
          fold::Fold};

/// Parses a list of variable names separated by commas
///
///     a, b, c
///
/// This is how the compiler passes in arguments to our attribute -- it is
/// everything inside the delimiters after the attribute name.
///
///     #[wlroots_dehandle(a, b, c)]
///
struct Args {
    vars: HashMap<Ident, bool>
}

impl Parse for Args {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
        Ok(Args {
            vars: vars.into_iter().map(|k| (k, false)).collect(),
        })
    }
}

impl Fold for Args {
    fn fold_block(&mut self, block: Block) -> Block {
        build_block(block.stmts.iter(), self)
    }
}

impl Args {
    fn is_handle(&mut self, name: Ident) -> bool {
        if let Some(seen) = self.vars.get_mut(&name) {
            *seen = true;
            true
        } else {
            false
        }
    }
}

/// Attribute to automatically call the `run` method on handles with the
/// remaining block of code.
///
/// The name of the variable you want to use as the upgraded handle should be
/// provided as an argument to the attribute. It does not need to be the same
/// as the handle variable.
///
/// The syntax in the code should be `use $handle as $upgraded_handle`.
/// E.g the variable in the code that stores the handle should go on the
/// **left** and the variable you used in the attribute declaration should
/// go on the **right**.
///
/// # Example
///
/// ```
/// impl InputManagerHandler for InputManager {
///     #[wlroots_dehandle(compositor, keyboard, seat)]
///     fn keyboard_added(&mut self,
///                       compositor_handle: CompositorHandle,
///                       keyboard: KeyboardHandle)
///                       -> Option<Box<Keyboard Handler>> {
///         {
///             use compositor_handle as compositor;
///             use keyboard as keyboard;
///             let server: &mut ::Server = compositor.into();
///             server.keyboards.push(keyboard.weak_reference());
///             // Now that we have at least one keyboard, update the seat capabilities.
///             let server_seat = &server.seat.seat;
///             use server_seat as seat;
///             let mut capabilities = seat.capabilities();
///             capabilities.insert(Capability::Keyboard);
///             seat.set_capabilities(capabilities);
///             seat.set_keyboard(keyboard.input_device());
///         }
///         // Due to some weird closure inference rules, this has to be outside
///         // of the above block.
///         Some(Box::new(::Keyboard))
///     }
/// }
/// ```
#[proc_macro_attribute]
pub fn wlroots_dehandle(args: TokenStream, input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as ItemFn);
    let mut args = parse_macro_input!(args as Args);
    if args.vars.len() == 0 {
        panic!("wlroots_dehandle requires at least one argument")
    }
    let output = args.fold_item_fn(input);
    for (arg, seen) in args.vars {
        if !seen {
            panic!(format!("Must use all declared handles, didn't use `{}`",
                           arg))
        }
    }
    TokenStream::from(quote!(#output))
}

fn build_block(mut input: std::slice::Iter<Stmt>, args: &mut Args) -> Block {
    let mut output = vec![];
    let mut inner = None;
    while let Some(stmt) = input.next().cloned() {
        use {Item::Use, UseTree::Rename};
        match stmt.clone() {
            Stmt::Item(Use(ItemUse { tree: Rename(use_stmt), ..})) => {
                if args.is_handle(use_stmt.rename.clone()) {
                    inner = Some((use_stmt.ident, use_stmt.rename));
                    break
                }
                output.push(stmt)
            },
            // Recurse into function body
            Stmt::Item(Item::Fn(mut function)) => {
                let inner_block = function.block.clone();
                *function.block = build_block(inner_block.stmts.iter(), args);
                output.push(Stmt::Item(Item::Fn(function)))
            },
            // Recurse into let call
            Stmt::Local(mut local) => {
                if let Some((_, body)) = local.init.clone() {
                    let body = build_block_expr(*body.clone(), args);
                    let body = parse_quote!(#body);
                    local.init.as_mut().unwrap().1 = body;
                    output.push(Stmt::Local(local))
                }
            },
            Stmt::Expr(expr) => {
                let body = build_block_expr(expr, args);
                output.push(parse_quote!({#body}))
            }
            Stmt::Semi(expr, _) => {
                let body = build_block_expr(expr, args);
                output.push(parse_quote!({#body;}))
            }
            _ => output.push(stmt)
        }
    }
    if let Some((handle, dehandle)) = inner {
        let inner_block = build_block(input, args);
        let handle_call = parse_quote!(
            {(#handle).run(|#dehandle|{
                #inner_block
            }).expect(concat!("Could not upgrade handle ",
                              stringify!(#handle), " to ",
                              stringify!(#dehandle)))}
        );
        output.push(handle_call);
    }
    parse_quote!({#(#output)*})
}

/// Tries to build a block from the expression.
fn build_block_expr(expr: Expr, args: &mut Args) -> Expr {
    match expr {
        Expr::Block(block) => {
            let block = build_block(block.block.stmts.iter(), args);
            parse_quote!(#block)
        }
        Expr::Let(mut let_expr) => {
            *let_expr.expr = build_block_expr(*let_expr.expr.clone(), args);
            Expr::Let(let_expr)
        },
        Expr::If(mut if_expr) => {
            let then_branch = if_expr.then_branch.clone();
            let then_branch = build_block_expr(parse_quote!(#then_branch), args);
            if_expr.then_branch = parse_quote!(#then_branch);
            if_expr.else_branch = match if_expr.else_branch.clone() {
                None => if_expr.else_branch,
                Some((token, else_branch)) => {
                    Some((token, Box::new( build_block_expr(*else_branch, args))))
                }
            };
            Expr::If(if_expr)
        },
        Expr::While(mut while_expr) => {
            let body = while_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            while_expr.body = parse_quote!(#body);
            Expr::While(while_expr)
        },
        Expr::ForLoop(mut for_expr) => {
            let body = for_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            for_expr.body = parse_quote!(#body);
            Expr::ForLoop(for_expr)
        },
        Expr::Loop(mut loop_expr) => {
            let body = loop_expr.body.clone();
            let body = build_block_expr(parse_quote!(#body), args);
            loop_expr.body = parse_quote!(#body);
            Expr::Loop(loop_expr)
        },
        Expr::Match(mut match_expr) => {
            for arm in &mut match_expr.arms {
                *arm.body = build_block_expr(*arm.body.clone(), args)
            }
            Expr::Match(match_expr)
        },
        Expr::Struct(mut struct_expr) => {
            for field in &mut struct_expr.fields {
                field.expr = build_block_expr(field.expr.clone(), args);
            }
            Expr::Struct(struct_expr)
        },
        Expr::Call(mut call_expr) => {
            for arg in &mut call_expr.args {
                *arg = build_block_expr(arg.clone(), args);
            }
            Expr::Call(call_expr)
        },
        Expr::MethodCall(mut call_expr) => {
            for arg in &mut call_expr.args {
                *arg = build_block_expr(arg.clone(), args);
            }
            Expr::MethodCall(call_expr)
        },
        Expr::Closure(mut closure_expr) => {
            *closure_expr.body = build_block_expr(*closure_expr.body.clone(),
                                                  args);
            Expr::Closure(closure_expr)
        },
        Expr::Unsafe(mut unsafe_expr) => {
            unsafe_expr.block = build_block(unsafe_expr.block.stmts.iter(),
                                            args);
            Expr::Unsafe(unsafe_expr)
        },
        Expr::Assign(mut assign_expr) => {
            *assign_expr.right = build_block_expr(*assign_expr.right.clone(),
                                                  args);
            Expr::Assign(assign_expr)
        },
        Expr::AssignOp(mut assign_expr) => {
            *assign_expr.right = build_block_expr(*assign_expr.right.clone(),
                                                  args);
            Expr::AssignOp(assign_expr)
        },
        Expr::Break(mut break_expr) => {
            match break_expr.expr {
                None => {},
                Some(ref mut expr) => {
                    **expr = build_block_expr(*expr.clone(), args);
                }
            }
            Expr::Break(break_expr)
        },
        Expr::Return(mut return_expr) => {
            match return_expr.expr {
                None => {},
                Some(ref mut expr) => {
                    **expr = build_block_expr(*expr.clone(), args);
                }
            }
            Expr::Return(return_expr)
        },
        Expr::Reference(mut reference_expr) => {
            *reference_expr.expr = build_block_expr(*reference_expr.expr.clone(),
                                                    args);
            Expr::Reference(reference_expr)
        },
        Expr::Paren(mut paren_expr) => {
            *paren_expr.expr = build_block_expr(*paren_expr.expr.clone(), args);
            Expr::Paren(paren_expr)
        },
        Expr::Unary(mut unary_expr) => {
            *unary_expr.expr = build_block_expr(*unary_expr.expr.clone(), args);
            Expr::Unary(unary_expr)
        },
        Expr::Binary(mut binary_expr) => {
            *binary_expr.left = build_block_expr(*binary_expr.left.clone(), args);
            *binary_expr.right = build_block_expr(*binary_expr.right.clone(), args);
            Expr::Binary(binary_expr)
        },
        v => {
            v
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul,Add};

pub struct Vec3<T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> {
    x: T,
    y: T,
    z: T,
}

impl <T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone> Vec3<T> {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_norm() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<commit_msg>Use where clauses for type bounds<commit_after>use std::ops::{Mul,Add};

pub struct Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone {
    x: T,
    y: T,
    z: T,
}

impl <T> Vec3<T> where T : Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_know_its_norm() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<|endoftext|>


<commit_before>/// Route53 TXT entries require quotations around their values.
/// Use this function to add quotes if needed. These examples show how
/// this adds quotes if needed:
/// ```ignore
/// let rr = vec![
///   ResourceRecord {
///     value: quote_txt_record("foo"),
///   },
///   ResourceRecord {
///     value: quote_txt_record("\"baz\""),
///   },
/// ];
/// ```
pub fn quote_txt_record(record_contents: &str) -> String {
    let mut quoted_string = String::from(record_contents);
    if !quoted_string.starts_with("\"") {
        quoted_string = format!("\"{}", quoted_string);
    }
    if !quoted_string.ends_with("\"") {
        quoted_string = format!("{}\"", quoted_string);
    }
    quoted_string
}
<commit_msg>Address remaining clippy lints for services.<commit_after>/// Route53 TXT entries require quotations around their values.
/// Use this function to add quotes if needed. These examples show how
/// this adds quotes if needed:
/// ```ignore
/// let rr = vec![
///   ResourceRecord {
///     value: quote_txt_record("foo"),
///   },
///   ResourceRecord {
///     value: quote_txt_record("\"baz\""),
///   },
/// ];
/// ```
pub fn quote_txt_record(record_contents: &str) -> String {
    let mut quoted_string = String::from(record_contents);
    if !quoted_string.starts_with('\"') {
        quoted_string = format!("\"{}", quoted_string);
    }
    if !quoted_string.ends_with('\"') {
        quoted_string = format!("{}\"", quoted_string);
    }
    quoted_string
}
<|endoftext|>