<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! This module defines all the gas parameters for transactions, along with their initial values
//! in the genesis and a mapping between the Rust representation and the on-chain gas schedule.

use crate::algebra::{FeePerGasUnit, Gas, GasScalingFactor, GasUnit};
use aptos_types::{
    on_chain_config::StorageGasSchedule, state_store::state_key::StateKey, write_set::WriteOp,
};
use move_core_types::gas_algebra::{
    InternalGas, InternalGasPerArg, InternalGasPerByte, InternalGasUnit, NumArgs, NumBytes,
    ToUnitFractionalWithParams, ToUnitWithParams,
};

#[derive(Clone, Debug)]
pub struct StorageGasParameters {
    pub per_item_read: InternalGasPerArg,
    pub per_item_create: InternalGasPerArg,
    pub per_item_write: InternalGasPerArg,
    pub per_byte_read: InternalGasPerByte,
    pub per_byte_create: InternalGasPerByte,
    pub per_byte_write: InternalGasPerByte,
}

impl From<StorageGasSchedule> for StorageGasParameters {
    fn from(gas_schedule: StorageGasSchedule) -> Self {
        Self {
            per_item_read: gas_schedule.per_item_read.into(),
            per_item_create: gas_schedule.per_item_create.into(),
            per_item_write: gas_schedule.per_item_write.into(),
            per_byte_read: gas_schedule.per_byte_read.into(),
            per_byte_create: gas_schedule.per_byte_create.into(),
            per_byte_write: gas_schedule.per_byte_write.into(),
        }
    }
}

impl StorageGasParameters {
    pub fn zeros() -> Self {
        Self {
            per_item_read: 0.into(),
            per_item_create: 0.into(),
            per_item_write: 0.into(),
            per_byte_read: 0.into(),
            per_byte_create: 0.into(),
            per_byte_write: 0.into(),
        }
    }
}

impl StorageGasParameters {
    pub fn calculate_write_set_gas<'a>(
        &self,
        ops: impl IntoIterator<Item = (&'a StateKey, &'a WriteOp)>,
    ) -> InternalGas {
        use WriteOp::*;

        let mut num_items_create = NumArgs::zero();
        let mut num_items_write = NumArgs::zero();
        let mut num_bytes_create = NumBytes::zero();
        let mut num_bytes_write = NumBytes::zero();

        for (key, op) in ops.into_iter() {
            let key_size = || {
                NumBytes::new(
                    key.encode()
                        .expect("Should be able to serialize state key")
                        .len() as u64,
                )
            };

            match op {
                Creation(data) => {
                    num_items_create += 1.into();

                    num_bytes_create += key_size();
                    num_bytes_create += NumBytes::new(data.len() as u64);
                }
                Modification(data) => {
                    num_items_write += 1.into();

                    num_bytes_write += key_size();
                    num_bytes_write += NumBytes::new(data.len() as u64);
                }
                Deletion => (),
            }
        }

        num_items_create * self.per_item_create
            + num_items_write * self.per_item_write
            + num_bytes_create * self.per_byte_create
            + num_bytes_write * self.per_byte_write
    }
}

crate::params::define_gas_parameters!(
    TransactionGasParameters,
    "txn",
    [
        // The flat minimum amount of gas required for any transaction.
        // Charged at the start of execution.
        [
            min_transaction_gas_units: InternalGas,
            "min_transaction_gas_units",
            600
        ],
        // Any transaction over this size will be charged an additional amount per byte.
        [
            large_transaction_cutoff: NumBytes,
            "large_transaction_cutoff",
            600
        ],
        // The units of gas that to be charged per byte over the `large_transaction_cutoff` in addition to
        // `min_transaction_gas_units` for transactions whose size exceeds `large_transaction_cutoff`.
        [
            intrinsic_gas_per_byte: InternalGasPerByte,
            "intrinsic_gas_per_byte",
            8
        ],
        // ~5 microseconds should equal one unit of computational gas. We bound the maximum
        // computational time of any given transaction at roughly 20 seconds. We want this number and
        // `MAX_PRICE_PER_GAS_UNIT` to always satisfy the inequality that
        // MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits<GasCarrier>::MAX)
        [
            maximum_number_of_gas_units: Gas,
            "maximum_number_of_gas_units",
            4_000_000
        ],
        // The minimum gas price that a transaction can be submitted with.
        // TODO(Gas): should probably change this to something > 0
        [
            min_price_per_gas_unit: FeePerGasUnit,
            "min_price_per_gas_unit",
            0
        ],
        // The maximum gas unit price that a transaction can be submitted with.
        [
            max_price_per_gas_unit: FeePerGasUnit,
            "max_price_per_gas_unit",
            10_000
        ],
        [
            max_transaction_size_in_bytes: NumBytes,
            "max_transaction_size_in_bytes",
            32 * 1024
        ],
        [
            gas_unit_scaling_factor: GasScalingFactor,
            "gas_unit_scaling_factor",
            1000
        ],
        // Gas Parameters for reading data from storage.
        [load_data_base: InternalGas, "load_data.base", 1],
        [
            load_data_per_byte: InternalGasPerByte,
            "load_data.per_byte",
            1
        ],
        [load_data_failure: InternalGas, "load_data.failure", 1],
        // Gas parameters for writing data to storage.
        [
            write_data_per_op: InternalGasPerArg,
            "write_data.per_op",
            100
        ],
        [
            write_data_per_new_item: InternalGasPerArg,
            "write_data.new_item",
            1000
        ],
        [
            write_data_per_byte_in_key: InternalGasPerByte,
            "write_data.per_byte_in_key",
            100
        ],
        [
            write_data_per_byte_in_val: InternalGasPerByte,
            "write_data.per_byte_in_val",
            100
        ],
    ]
);

impl TransactionGasParameters {
    // TODO(Gas): Right now we are relying on this to avoid div by zero errors when using the all-zero
    //            gas parameters. See if there's a better way we can handle this.
    fn scaling_factor(&self) -> GasScalingFactor {
        match u64::from(self.gas_unit_scaling_factor) {
            0 => 1.into(),
            x => x.into(),
        }
    }

    /// Calculate the intrinsic gas for the transaction based upon its size in bytes.
    pub fn calculate_intrinsic_gas(&self, transaction_size: NumBytes) -> InternalGas {
        let min_transaction_fee = self.min_transaction_gas_units;

        if transaction_size > self.large_transaction_cutoff {
            let excess = transaction_size
                .checked_sub(self.large_transaction_cutoff)
                .unwrap();
            min_transaction_fee + (excess * self.intrinsic_gas_per_byte)
        } else {
            min_transaction_fee
        }
    }

    pub fn calculate_write_set_gas<'a>(
        &self,
        ops: impl IntoIterator<Item = (&'a StateKey, &'a WriteOp)>,
    ) -> InternalGas {
        use WriteOp::*;

        // Counting
        let mut num_ops = NumArgs::zero();
        let mut num_new_items = NumArgs::zero();
        let mut num_bytes_key = NumBytes::zero();
        let mut num_bytes_val = NumBytes::zero();

        for (key, op) in ops.into_iter() {
            num_ops += 1.into();

            if self.write_data_per_byte_in_key > 0.into() {
                // TODO(Gas): Are we supposed to panic here?
                num_bytes_key += NumBytes::new(
                    key.encode()
                        .expect("Should be able to serialize state key")
                        .len() as u64,
                );
            }

            match op {
                Creation(data) => {
                    num_new_items += 1.into();
                    num_bytes_val += NumBytes::new(data.len() as u64);
                }
                Modification(data) => {
                    num_bytes_val += NumBytes::new(data.len() as u64);
                }
                Deletion => (),
            }
        }

        // Calculate the costs
        let cost_ops = self.write_data_per_op * num_ops;
        let cost_new_items = self.write_data_per_new_item * num_new_items;
        let cost_bytes = self.write_data_per_byte_in_key * num_bytes_key
            + self.write_data_per_byte_in_val * num_bytes_val;

        cost_ops + cost_new_items + cost_bytes
    }
}

impl ToUnitWithParams<InternalGasUnit> for GasUnit {
    type Params = TransactionGasParameters;

    fn multiplier(params: &Self::Params) -> u64 {
        params.scaling_factor().into()
    }
}

impl ToUnitFractionalWithParams<GasUnit> for InternalGasUnit {
    type Params = TransactionGasParameters;

    fn ratio(params: &Self::Params) -> (u64, u64) {
        (1, params.scaling_factor().into())
    }
}
<commit_msg>[gas] bump txn limit to 64K<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! This module defines all the gas parameters for transactions, along with their initial values
//! in the genesis and a mapping between the Rust representation and the on-chain gas schedule.

use crate::algebra::{FeePerGasUnit, Gas, GasScalingFactor, GasUnit};
use aptos_types::{
    on_chain_config::StorageGasSchedule, state_store::state_key::StateKey, write_set::WriteOp,
};
use move_core_types::gas_algebra::{
    InternalGas, InternalGasPerArg, InternalGasPerByte, InternalGasUnit, NumArgs, NumBytes,
    ToUnitFractionalWithParams, ToUnitWithParams,
};

#[derive(Clone, Debug)]
pub struct StorageGasParameters {
    pub per_item_read: InternalGasPerArg,
    pub per_item_create: InternalGasPerArg,
    pub per_item_write: InternalGasPerArg,
    pub per_byte_read: InternalGasPerByte,
    pub per_byte_create: InternalGasPerByte,
    pub per_byte_write: InternalGasPerByte,
}

impl From<StorageGasSchedule> for StorageGasParameters {
    fn from(gas_schedule: StorageGasSchedule) -> Self {
        Self {
            per_item_read: gas_schedule.per_item_read.into(),
            per_item_create: gas_schedule.per_item_create.into(),
            per_item_write: gas_schedule.per_item_write.into(),
            per_byte_read: gas_schedule.per_byte_read.into(),
            per_byte_create: gas_schedule.per_byte_create.into(),
            per_byte_write: gas_schedule.per_byte_write.into(),
        }
    }
}

impl StorageGasParameters {
    pub fn zeros() -> Self {
        Self {
            per_item_read: 0.into(),
            per_item_create: 0.into(),
            per_item_write: 0.into(),
            per_byte_read: 0.into(),
            per_byte_create: 0.into(),
            per_byte_write: 0.into(),
        }
    }
}

impl StorageGasParameters {
    pub fn calculate_write_set_gas<'a>(
        &self,
        ops: impl IntoIterator<Item = (&'a StateKey, &'a WriteOp)>,
    ) -> InternalGas {
        use WriteOp::*;

        let mut num_items_create = NumArgs::zero();
        let mut num_items_write = NumArgs::zero();
        let mut num_bytes_create = NumBytes::zero();
        let mut num_bytes_write = NumBytes::zero();

        for (key, op) in ops.into_iter() {
            let key_size = || {
                NumBytes::new(
                    key.encode()
                        .expect("Should be able to serialize state key")
                        .len() as u64,
                )
            };

            match op {
                Creation(data) => {
                    num_items_create += 1.into();

                    num_bytes_create += key_size();
                    num_bytes_create += NumBytes::new(data.len() as u64);
                }
                Modification(data) => {
                    num_items_write += 1.into();

                    num_bytes_write += key_size();
                    num_bytes_write += NumBytes::new(data.len() as u64);
                }
                Deletion => (),
            }
        }

        num_items_create * self.per_item_create
            + num_items_write * self.per_item_write
            + num_bytes_create * self.per_byte_create
            + num_bytes_write * self.per_byte_write
    }
}

crate::params::define_gas_parameters!(
    TransactionGasParameters,
    "txn",
    [
        // The flat minimum amount of gas required for any transaction.
        // Charged at the start of execution.
        [
            min_transaction_gas_units: InternalGas,
            "min_transaction_gas_units",
            600
        ],
        // Any transaction over this size will be charged an additional amount per byte.
        [
            large_transaction_cutoff: NumBytes,
            "large_transaction_cutoff",
            600
        ],
        // The units of gas that to be charged per byte over the `large_transaction_cutoff` in addition to
        // `min_transaction_gas_units` for transactions whose size exceeds `large_transaction_cutoff`.
        [
            intrinsic_gas_per_byte: InternalGasPerByte,
            "intrinsic_gas_per_byte",
            8
        ],
        // ~5 microseconds should equal one unit of computational gas. We bound the maximum
        // computational time of any given transaction at roughly 20 seconds. We want this number and
        // `MAX_PRICE_PER_GAS_UNIT` to always satisfy the inequality that
        // MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits<GasCarrier>::MAX)
        [
            maximum_number_of_gas_units: Gas,
            "maximum_number_of_gas_units",
            4_000_000
        ],
        // The minimum gas price that a transaction can be submitted with.
        // TODO(Gas): should probably change this to something > 0
        [
            min_price_per_gas_unit: FeePerGasUnit,
            "min_price_per_gas_unit",
            0
        ],
        // The maximum gas unit price that a transaction can be submitted with.
        [
            max_price_per_gas_unit: FeePerGasUnit,
            "max_price_per_gas_unit",
            10_000
        ],
        [
            max_transaction_size_in_bytes: NumBytes,
            "max_transaction_size_in_bytes",
            64 * 1024
        ],
        [
            gas_unit_scaling_factor: GasScalingFactor,
            "gas_unit_scaling_factor",
            1000
        ],
        // Gas Parameters for reading data from storage.
        [load_data_base: InternalGas, "load_data.base", 1],
        [
            load_data_per_byte: InternalGasPerByte,
            "load_data.per_byte",
            1
        ],
        [load_data_failure: InternalGas, "load_data.failure", 1],
        // Gas parameters for writing data to storage.
        [
            write_data_per_op: InternalGasPerArg,
            "write_data.per_op",
            100
        ],
        [
            write_data_per_new_item: InternalGasPerArg,
            "write_data.new_item",
            1000
        ],
        [
            write_data_per_byte_in_key: InternalGasPerByte,
            "write_data.per_byte_in_key",
            100
        ],
        [
            write_data_per_byte_in_val: InternalGasPerByte,
            "write_data.per_byte_in_val",
            100
        ],
    ]
);

impl TransactionGasParameters {
    // TODO(Gas): Right now we are relying on this to avoid div by zero errors when using the all-zero
    //            gas parameters. See if there's a better way we can handle this.
    fn scaling_factor(&self) -> GasScalingFactor {
        match u64::from(self.gas_unit_scaling_factor) {
            0 => 1.into(),
            x => x.into(),
        }
    }

    /// Calculate the intrinsic gas for the transaction based upon its size in bytes.
    pub fn calculate_intrinsic_gas(&self, transaction_size: NumBytes) -> InternalGas {
        let min_transaction_fee = self.min_transaction_gas_units;

        if transaction_size > self.large_transaction_cutoff {
            let excess = transaction_size
                .checked_sub(self.large_transaction_cutoff)
                .unwrap();
            min_transaction_fee + (excess * self.intrinsic_gas_per_byte)
        } else {
            min_transaction_fee
        }
    }

    pub fn calculate_write_set_gas<'a>(
        &self,
        ops: impl IntoIterator<Item = (&'a StateKey, &'a WriteOp)>,
    ) -> InternalGas {
        use WriteOp::*;

        // Counting
        let mut num_ops = NumArgs::zero();
        let mut num_new_items = NumArgs::zero();
        let mut num_bytes_key = NumBytes::zero();
        let mut num_bytes_val = NumBytes::zero();

        for (key, op) in ops.into_iter() {
            num_ops += 1.into();

            if self.write_data_per_byte_in_key > 0.into() {
                // TODO(Gas): Are we supposed to panic here?
                num_bytes_key += NumBytes::new(
                    key.encode()
                        .expect("Should be able to serialize state key")
                        .len() as u64,
                );
            }

            match op {
                Creation(data) => {
                    num_new_items += 1.into();
                    num_bytes_val += NumBytes::new(data.len() as u64);
                }
                Modification(data) => {
                    num_bytes_val += NumBytes::new(data.len() as u64);
                }
                Deletion => (),
            }
        }

        // Calculate the costs
        let cost_ops = self.write_data_per_op * num_ops;
        let cost_new_items = self.write_data_per_new_item * num_new_items;
        let cost_bytes = self.write_data_per_byte_in_key * num_bytes_key
            + self.write_data_per_byte_in_val * num_bytes_val;

        cost_ops + cost_new_items + cost_bytes
    }
}

impl ToUnitWithParams<InternalGasUnit> for GasUnit {
    type Params = TransactionGasParameters;

    fn multiplier(params: &Self::Params) -> u64 {
        params.scaling_factor().into()
    }
}

impl ToUnitFractionalWithParams<GasUnit> for InternalGasUnit {
    type Params = TransactionGasParameters;

    fn ratio(params: &Self::Params) -> (u64, u64) {
        (1, params.scaling_factor().into())
    }
}
<|endoftext|>


<commit_before>
#[ allow( unused_imports ) ]
use wstring_tools as TheModule;
mod inc;
<commit_msg>!test<commit_after>

#[ allow( unused_imports ) ]
use wstring_tools as TheModule;
mod inc;
<|endoftext|>


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

//! Functions for randomly accessing and sampling sequences.

use super::Rng;
use std::collections::hash_map::HashMap;

/// Randomly sample *up to* `amount` elements from a finite iterator.
///
/// The values are non-repeating but the order of elements returned is *not* random.
///
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
///
/// > If `len(iterable) <= amount` then the values will be in sequential order. In all other
/// > cases the order of the elements is neither random nor guaranteed.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let sample = seq::sample_iter(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
    where I: IntoIterator<Item=T>,
          R: Rng,
{
    let mut iter = iterable.into_iter();
    let mut reservoir = Vec::with_capacity(amount);
    reservoir.extend(iter.by_ref().take(amount));

    // continue unless the iterator was exhausted
    //
    // note: this prevents iterators that "restart" from causing problems.
    // If the iterator stops once, then so do we.
    if reservoir.len() == amount {
        for (i, elem) in iter.enumerate() {
            let k = rng.gen_range(0, i + 1 + amount);
            if let Some(spot) = reservoir.get_mut(k) {
                *spot = elem;
            }
        }
    } else {
        // Don't hang onto extra memory. There is a corner case where
        // `amount <<< len(iterable)` that we want to avoid.
        reservoir.shrink_to_fit();
    }
    reservoir
}

/// Randomly sample exactly `amount` values from `slice`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
/// ```
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
    where R: Rng,
          T: Clone
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| slice[*i].clone()));
    out
}

/// Randomly sample exactly `amount` references from `slice`.
///
/// The references are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
/// ```
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
    where R: Rng
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| &slice[*i]));
    out
}

/// Randomly sample exactly `amount` indices from `0..length`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
/// have the indices themselves so this is provided as an alternative.
///
/// Panics if `amount > self.len()`
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    if amount > length {
        panic!("`amount` must be less than or equal to `slice.len()`");
    }

    // We are going to have to allocate at least `amount` for the output no matter what. However,
    // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
    // it inserts an element for every loop.
    //
    // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
    //
    // TODO: there is probably even more fine-tuning that can be done here since
    // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
    // and a trade off could probably be made between memory/cpu, since hashmap operations
    // are slower than array index swapping.
    if amount >= length / 2 {
        sample_indices_inplace(rng, length, amount)
    } else {
        sample_indices_cache(rng, length, amount)
    }
}

/// Sample an amount of indices using an inplace partial fisher yates method.
///
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
/// It then truncates to `amount` and returns.
///
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
/// require allocating an extra cache and is much faster.
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut indices: Vec<usize> = Vec::with_capacity(length);
    indices.extend(0..length);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);
        let tmp = indices[i];
        indices[i] = indices[j];
        indices[j] = tmp;
    }
    indices.truncate(amount);
    debug_assert_eq!(indices.len(), amount);
    indices
}

/// This method performs a partial fisher-yates on a range of indices using a HashMap
/// as a cache to record potential collisions.
///
/// The cache avoids allocating the entire `length` of values. This is especially useful when
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
fn sample_indices_cache<R>(
    rng: &mut R,
    length: usize,
    amount: usize,
) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut cache = HashMap::with_capacity(amount);
    let mut out = Vec::with_capacity(amount);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);

        // equiv: let tmp = slice[i];
        let tmp = match cache.get(&i) {
            Some(e) => *e,
            None => i,
        };

        // equiv: slice[i] = slice[j];
        let x = match cache.get(&j) {
            Some(x) => *x,
            None => j,
        };

        // equiv: slice[j] = tmp;
        cache.insert(j, tmp);

        // note that in the inplace version, slice[i] is automatically "returned" value
        out.push(x);
    }
    debug_assert_eq!(out.len(), amount);
    out
}

#[cfg(test)]
mod test {
    use super::*;
    use {thread_rng, XorShiftRng, SeedableRng};

    #[test]
    fn test_sample_iter() {
        let min_val = 1;
        let max_val = 100;

        let mut r = thread_rng();
        let vals = (min_val..max_val).collect::<Vec<i32>>();
        let small_sample = sample_iter(&mut r, vals.iter(), 5);
        let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5);

        assert_eq!(small_sample.len(), 5);
        assert_eq!(large_sample.len(), vals.len());

        assert!(small_sample.iter().all(|e| {
            **e >= min_val && **e <= max_val
        }));
    }
    #[test]
    fn test_sample_slice_boundaries() {
        let empty: &[u8] = &[];

        let mut r = thread_rng();

        // sample 0 items
        assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
        assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);

        // sample 1 item
        assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
        let v = sample_slice(&mut r, &[1, 42], 1)[0];
        assert!(v == 1 || v == 42);

        // sample "all" the items
        let v = sample_slice(&mut r, &[42, 133], 2);
        assert!(v == vec![42, 133] || v == vec![133, 42]);

        assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);

        assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);

    }

    #[test]
    fn test_sample_slice() {
        let xor_rng = XorShiftRng::from_seed;

        let max_range = 100;
        let mut r = thread_rng();

        for length in 1usize..max_range {
            let amount = r.gen_range(0, length);
            let seed: [u32; 4] = [
                r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
            ];

            println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);

            // assert that the two index methods give exactly the same result
            let inplace = sample_indices_inplace(
                &mut xor_rng(seed), length, amount);
            let cache = sample_indices_cache(
                &mut xor_rng(seed), length, amount);
            assert_eq!(inplace, cache);

            // assert the basics work
            let regular = sample_indices(
                &mut xor_rng(seed), length, amount);
            assert_eq!(regular.len(), amount);
            assert!(regular.iter().all(|e| *e < length));
            assert_eq!(regular, inplace);

            // also test that sampling the slice works
            let vec: Vec<usize> = (0..length).collect();
            {
                let result = sample_slice(&mut xor_rng(seed), &vec, amount);
                assert_eq!(result, regular);
            }

            {
                let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
                let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
                assert_eq!(result, expected);
            }
        }
    }
}
<commit_msg>add distribution test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Functions for randomly accessing and sampling sequences.

use super::Rng;
use std::collections::hash_map::HashMap;

/// Randomly sample *up to* `amount` elements from a finite iterator.
///
/// The values are non-repeating but the order of elements returned is *not* random.
///
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
///
/// > If `len(iterable) <= amount` then the values will be in sequential order. In all other
/// > cases the order of the elements is neither random nor guaranteed.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let sample = seq::sample_iter(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
    where I: IntoIterator<Item=T>,
          R: Rng,
{
    let mut iter = iterable.into_iter();
    let mut reservoir = Vec::with_capacity(amount);
    reservoir.extend(iter.by_ref().take(amount));

    // continue unless the iterator was exhausted
    //
    // note: this prevents iterators that "restart" from causing problems.
    // If the iterator stops once, then so do we.
    if reservoir.len() == amount {
        for (i, elem) in iter.enumerate() {
            let k = rng.gen_range(0, i + 1 + amount);
            if let Some(spot) = reservoir.get_mut(k) {
                *spot = elem;
            }
        }
    } else {
        // Don't hang onto extra memory. There is a corner case where
        // `amount <<< len(iterable)` that we want to avoid.
        reservoir.shrink_to_fit();
    }
    reservoir
}

/// Randomly sample exactly `amount` values from `slice`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
/// ```
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
    where R: Rng,
          T: Clone
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| slice[*i].clone()));
    out
}

/// Randomly sample exactly `amount` references from `slice`.
///
/// The references are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
/// ```
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
    where R: Rng
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| &slice[*i]));
    out
}

/// Randomly sample exactly `amount` indices from `0..length`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
/// have the indices themselves so this is provided as an alternative.
///
/// Panics if `amount > self.len()`
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    if amount > length {
        panic!("`amount` must be less than or equal to `slice.len()`");
    }

    // We are going to have to allocate at least `amount` for the output no matter what. However,
    // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
    // it inserts an element for every loop.
    //
    // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
    //
    // TODO: there is probably even more fine-tuning that can be done here since
    // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
    // and a trade off could probably be made between memory/cpu, since hashmap operations
    // are slower than array index swapping.
    if amount >= length / 2 {
        sample_indices_inplace(rng, length, amount)
    } else {
        sample_indices_cache(rng, length, amount)
    }
}

/// Sample an amount of indices using an inplace partial fisher yates method.
///
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
/// It then truncates to `amount` and returns.
///
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
/// require allocating an extra cache and is much faster.
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut indices: Vec<usize> = Vec::with_capacity(length);
    indices.extend(0..length);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);
        let tmp = indices[i];
        indices[i] = indices[j];
        indices[j] = tmp;
    }
    indices.truncate(amount);
    debug_assert_eq!(indices.len(), amount);
    indices
}

/// This method performs a partial fisher-yates on a range of indices using a HashMap
/// as a cache to record potential collisions.
///
/// The cache avoids allocating the entire `length` of values. This is especially useful when
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
fn sample_indices_cache<R>(
    rng: &mut R,
    length: usize,
    amount: usize,
) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut cache = HashMap::with_capacity(amount);
    let mut out = Vec::with_capacity(amount);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);

        // equiv: let tmp = slice[i];
        let tmp = match cache.get(&i) {
            Some(e) => *e,
            None => i,
        };

        // equiv: slice[i] = slice[j];
        let x = match cache.get(&j) {
            Some(x) => *x,
            None => j,
        };

        // equiv: slice[j] = tmp;
        cache.insert(j, tmp);

        // note that in the inplace version, slice[i] is automatically "returned" value
        out.push(x);
    }
    debug_assert_eq!(out.len(), amount);
    out
}

#[cfg(test)]
mod test {
    use super::*;
    use {thread_rng, XorShiftRng, SeedableRng};

    #[test]
    fn test_sample_iter() {
        let min_val = 1;
        let max_val = 100;

        let mut r = thread_rng();
        let vals = (min_val..max_val).collect::<Vec<i32>>();
        let small_sample = sample_iter(&mut r, vals.iter(), 5);
        let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5);

        assert_eq!(small_sample.len(), 5);
        assert_eq!(large_sample.len(), vals.len());

        assert!(small_sample.iter().all(|e| {
            **e >= min_val && **e <= max_val
        }));
    }
    #[test]
    fn test_sample_slice_boundaries() {
        let empty: &[u8] = &[];

        let mut r = thread_rng();

        // sample 0 items
        assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
        assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);

        // sample 1 item
        assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
        let v = sample_slice(&mut r, &[1, 42], 1)[0];
        assert!(v == 1 || v == 42);

        // sample "all" the items
        let v = sample_slice(&mut r, &[42, 133], 2);
        assert!(v == vec![42, 133] || v == vec![133, 42]);

        assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);

        assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);

        // Make sure lucky 777's aren't lucky
        let slice = &[42, 777];
        let mut num_42 = 0;
        let total = 1000;
        for _ in 0..total {
            let v = sample_slice(&mut r, slice, 1);
            assert_eq!(v.len(), 1);
            let v = v[0];
            assert!(v == 42 || v == 777);
            if v == 42 {
                num_42 += 1;
            }
        }
        let ratio_42 = num_42 as f64 / 1000 as f64;
        assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42);
    }

    #[test]
    fn test_sample_slice() {
        let xor_rng = XorShiftRng::from_seed;

        let max_range = 100;
        let mut r = thread_rng();

        for length in 1usize..max_range {
            let amount = r.gen_range(0, length);
            let seed: [u32; 4] = [
                r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
            ];

            println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);

            // assert that the two index methods give exactly the same result
            let inplace = sample_indices_inplace(
                &mut xor_rng(seed), length, amount);
            let cache = sample_indices_cache(
                &mut xor_rng(seed), length, amount);
            assert_eq!(inplace, cache);

            // assert the basics work
            let regular = sample_indices(
                &mut xor_rng(seed), length, amount);
            assert_eq!(regular.len(), amount);
            assert!(regular.iter().all(|e| *e < length));
            assert_eq!(regular, inplace);

            // also test that sampling the slice works
            let vec: Vec<usize> = (0..length).collect();
            {
                let result = sample_slice(&mut xor_rng(seed), &vec, amount);
                assert_eq!(result, regular);
            }

            {
                let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
                let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
                assert_eq!(result, expected);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate rustler;
#[macro_use] extern crate rustler_codegen;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate pact_mock_server;
extern crate libc;

use rustler::{NifEnv, NifTerm, NifResult, NifEncoder};
use pact_mock_server::create_mock_server;
use pact_mock_server::MockServerError;
use pact_mock_server::mock_server_mismatches;
use pact_mock_server::mock_server_matched;
use pact_mock_server::write_pact_file;
use pact_mock_server::WritePactFileErr;
use pact_mock_server::cleanup_mock_server_ffi;
use std::ffi::CString;
use std::ffi::CStr;
mod atoms {
    rustler_atoms! {
        atom ok;
        atom error;
        atom mock_server_failed_to_start;
        atom invalid_pact_json;
        atom io_error;
        atom no_mock_server_running_on_port;
        //atom __true__ = "true";
        //atom __false__ = "false";
    }
}

rustler_export_nifs! {
    "Elixir.PactElixir.RustPactMockServerFacade",
    [
        ("create_mock_server", 2, create_mock_server_call),
        ("mock_server_mismatches", 1, mock_server_mismatches_call),
        ("mock_server_matched", 1, mock_server_matched_call),
        ("write_pact_file", 2, write_pact_file_call),
        ("cleanup_mock_server", 1, cleanup_mock_server_call)
    ],
    None
}

fn create_mock_server_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let pact_json: &str = try!(args[0].decode());
    let port_arg: i32 = try!(args[1].decode());

    match create_mock_server(pact_json, port_arg) {
        Ok(port) =>
            Ok((atoms::ok(), port).encode(env)),
        Err(MockServerError::MockServerFailedToStart) =>
            Ok((atoms::error(), atoms::mock_server_failed_to_start()).encode(env)),
        Err(MockServerError::InvalidPactJson) =>
            Ok((atoms::error(), atoms::invalid_pact_json()).encode(env))
    }
}

fn mock_server_mismatches_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());
    // TODO: This works only because mock_server_mismatches returns a string now:
    // Calling to_string() on json!(mismatches) in pact-reference/rust/pact_mock_server/src/lib.rs:657
    Ok((atoms::ok(), mock_server_mismatches(port)).encode(env))
}

fn mock_server_matched_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());

    let matched: bool = mock_server_matched(port);

    Ok((atoms::ok(), matched).encode(env))
}

fn write_pact_file_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());
    let dir_path: String = try!(args[1].decode());

    match write_pact_file(port, Some(dir_path)) {
        Ok(_result) =>
            Ok((atoms::ok()).encode(env)),
        /// IO Error occured
        Err(WritePactFileErr::IOError) =>
            Ok((atoms::error(), atoms::io_error()).encode(env)),
        /// No mock server was running on the port
        Err(WritePactFileErr::NoMockServer) =>
            Ok((atoms::error(), atoms::no_mock_server_running_on_port()).encode(env))
    }
}

fn cleanup_mock_server_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());

    let success: bool = cleanup_mock_server_ffi(port);

    Ok((atoms::ok(), success).encode(env))
}

<commit_msg>Use Rust version of cleanup_moc_server aka. shutdown_mock_server_by_port<commit_after>#[macro_use] extern crate rustler;
#[macro_use] extern crate rustler_codegen;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate pact_mock_server;
extern crate libc;

use rustler::{NifEnv, NifTerm, NifResult, NifEncoder};
use pact_mock_server::create_mock_server;
use pact_mock_server::MockServerError;
use pact_mock_server::mock_server_mismatches;
use pact_mock_server::mock_server_matched;
use pact_mock_server::write_pact_file;
use pact_mock_server::WritePactFileErr;
use pact_mock_server::shutdown_mock_server_by_port;
mod atoms {
    rustler_atoms! {
        atom ok;
        atom error;
        atom mock_server_failed_to_start;
        atom invalid_pact_json;
        atom io_error;
        atom no_mock_server_running_on_port;
        //atom __true__ = "true";
        //atom __false__ = "false";
    }
}

rustler_export_nifs! {
    "Elixir.PactElixir.RustPactMockServerFacade",
    [
        ("create_mock_server", 2, create_mock_server_call),
        ("mock_server_mismatches", 1, mock_server_mismatches_call),
        ("mock_server_matched", 1, mock_server_matched_call),
        ("write_pact_file", 2, write_pact_file_call),
        ("cleanup_mock_server", 1, cleanup_mock_server_call)
    ],
    None
}

fn create_mock_server_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let pact_json: &str = try!(args[0].decode());
    let port_arg: i32 = try!(args[1].decode());

    match create_mock_server(pact_json, port_arg) {
        Ok(port) =>
            Ok((atoms::ok(), port).encode(env)),
        Err(MockServerError::MockServerFailedToStart) =>
            Ok((atoms::error(), atoms::mock_server_failed_to_start()).encode(env)),
        Err(MockServerError::InvalidPactJson) =>
            Ok((atoms::error(), atoms::invalid_pact_json()).encode(env))
    }
}

fn mock_server_mismatches_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());
    // TODO: This works only because mock_server_mismatches returns a string now:
    // Calling to_string() on json!(mismatches) in pact-reference/rust/pact_mock_server/src/lib.rs:657
    Ok((atoms::ok(), mock_server_mismatches(port)).encode(env))
}

fn mock_server_matched_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());

    let matched: bool = mock_server_matched(port);

    Ok((atoms::ok(), matched).encode(env))
}

fn write_pact_file_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());
    let dir_path: String = try!(args[1].decode());

    match write_pact_file(port, Some(dir_path)) {
        Ok(_result) =>
            Ok((atoms::ok()).encode(env)),
        /// IO Error occured
        Err(WritePactFileErr::IOError) =>
            Ok((atoms::error(), atoms::io_error()).encode(env)),
        /// No mock server was running on the port
        Err(WritePactFileErr::NoMockServer) =>
            Ok((atoms::error(), atoms::no_mock_server_running_on_port()).encode(env))
    }
}

fn cleanup_mock_server_call<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let port: i32 = try!(args[0].decode());

    Ok((atoms::ok(), shutdown_mock_server_by_port(port)).encode(env))
}

<|endoftext|>


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

use dbcache::{self, BasicSet, IndexSet, InstaSet};
use hab_net::server::Envelope;
use protobuf::RepeatedField;
use protocol::net::{self, NetOk, ErrCode};
use protocol::vault as proto;
use zmq;

use super::ServerState;
use error::Result;

pub fn account_invitation_list(req: &mut Envelope,
                               sock: &mut zmq::Socket,
                               state: &mut ServerState)
                               -> Result<()> {
    let msg: proto::AccountInvitationListRequest = try!(req.parse_msg());
    let invites = try!(state.datastore.origins.invites.get_by_account_id(msg.get_account_id()));
    debug!("Got invites for account {} ", &msg.get_account_id());
    let mut resp = proto::AccountInvitationListResponse::new();
    resp.set_account_id(msg.get_account_id());

    let mut r_invites = RepeatedField::new();
    for invite in invites {
        r_invites.push(invite);
    }
    resp.set_invitations(r_invites);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_check_access(req: &mut Envelope,
                           sock: &mut zmq::Socket,
                           state: &mut ServerState)
                           -> Result<()> {
    let msg: proto::CheckOriginAccessRequest = try!(req.parse_msg());
    let is_member = try!(state.datastore
        .origins
        .is_origin_member(msg.get_account_id(), msg.get_origin_name()));
    let mut resp = proto::CheckOriginAccessResponse::new();
    resp.set_has_access(is_member);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_create(req: &mut Envelope,
                     sock: &mut zmq::Socket,
                     state: &mut ServerState)
                     -> Result<()> {
    let msg: proto::OriginCreate = try!(req.parse_msg());
    let mut origin = proto::Origin::new();
    origin.set_name(msg.get_name().to_string());
    origin.set_owner_id(msg.get_owner_id());
    if let Ok(_origin) = state.datastore
        .origins
        .name_idx
        .find(&msg.get_name().to_string()) {
        let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-create:0");
        try!(req.reply_complete(sock, &err));
    }
    try!(state.datastore.origins.write(&mut origin));
    debug!("Adding owner as origin member: {}", &msg.get_owner_name());
    try!(state.datastore
        .origins
        .add_origin_member(msg.get_owner_id(), msg.get_owner_name(), msg.get_name()));
    try!(req.reply_complete(sock, &origin));
    Ok(())
}

pub fn origin_get(req: &mut Envelope,
                  sock: &mut zmq::Socket,
                  state: &mut ServerState)
                  -> Result<()> {
    let mut msg: proto::OriginGet = try!(req.parse_msg());
    match state.datastore.origins.name_idx.find(&msg.take_name()) {
        Ok(origin_id) => {
            let mut origin = state.datastore.origins.find(&origin_id).unwrap();

            match state.datastore.origins.key_idx.find(&origin.get_name().to_string()) {
                Ok(key_id) => {
                    let secret_key =
                        state.datastore.origins.origin_secret_keys.find(&key_id).unwrap();
                    origin.set_private_key_name(format!("{}-{}",
                                                        secret_key.get_name(),
                                                        secret_key.get_revision()));
                }
                Err(e) => debug!("error looking for secret key {:?}", e),
            };

            try!(req.reply_complete(sock, &origin));
        }
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:origin-get:1");
            try!(req.reply_complete(sock, &err));
        }
        Err(e) => {
            error!("OriginGet, err={:?}", e);
            let err = net::err(ErrCode::BUG, "vt:origin-get:0");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn origin_invitation_accept(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginInvitationAcceptRequest = try!(req.parse_msg());
    match state.datastore.origins.invites.find(&msg.get_invite_id()) {
        Ok(invite) => {
            debug!("REQ    {:?}", &msg);
            debug!("INVITE {:?}", &invite);
            if msg.get_account_accepting_request() != invite.get_account_id() {
                let err = net::err(ErrCode::ACCESS_DENIED, "vt:origin-invite-accept:0");
                try!(req.reply_complete(sock, &err));
            }

            match state.datastore.origins.modify_invite(&invite, msg.get_ignore()) {
                Ok(()) => (),
                Err(e) => {
                    debug!("Error accepting invite: {}", e);
                }
            };
        }
        Err(e) => {
            debug!("Error accepting invite, maybe it's already been accepted? {}",
                   e);
        }
    };

    let resp = proto::OriginInvitationAcceptResponse::new();
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_invitation_create(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginInvitationCreate = try!(req.parse_msg());
    let mut invitation = proto::OriginInvitation::new();
    if !try!(state.datastore
        .origins
        .is_origin_member(msg.get_account_id(), msg.get_origin_name())) {
        debug!("Can't invite to this org unless your already a member");
        let err = net::err(ErrCode::ACCESS_DENIED, "vt:origin-create:0");
        try!(req.reply_complete(sock, &err));
    }

    let existing_invites =
        try!(state.datastore.origins.invites.get_by_account_id(msg.get_account_id()));

    for invite in &existing_invites {
        if invite.get_origin_name() == msg.get_origin_name() {
            debug!("Invite for origin {} for user {} already exists",
                   &msg.get_origin_name(),
                   &msg.get_account_name());
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-create:1");
            try!(req.reply_complete(sock, &err));
            return Ok(());
        }
    }

    invitation.set_account_id(msg.get_account_id());
    invitation.set_account_name(msg.get_account_name().to_string());
    invitation.set_origin_id(msg.get_origin_id());
    invitation.set_origin_name(msg.get_origin_name().to_string());
    invitation.set_owner_id(msg.get_owner_id());

    try!(state.datastore.origins.invites.write(&mut invitation));
    try!(req.reply_complete(sock, &invitation));
    Ok(())
}

pub fn origin_invitation_list(req: &mut Envelope,
                              sock: &mut zmq::Socket,
                              state: &mut ServerState)
                              -> Result<()> {
    let msg: proto::OriginInvitationListRequest = try!(req.parse_msg());
    let invites = try!(state.datastore
        .origins
        .invites
        .get_by_origin_id(msg.get_origin_id()));
    let mut resp = proto::OriginInvitationListResponse::new();
    resp.set_origin_id(msg.get_origin_id());
    let mut r_invites = RepeatedField::new();
    for invite in invites {
        r_invites.push(invite);
    }
    resp.set_invitations(r_invites);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_list(req: &mut Envelope,
                   sock: &mut zmq::Socket,
                   _state: &mut ServerState)
                   -> Result<()> {
    let origin1 = proto::Origin::new();
    let origin2 = proto::Origin::new();
    let origins = vec![origin1, origin2];
    for (i, origin) in origins.iter().enumerate() {
        if i == origins.len() {
            try!(req.reply_complete(sock, origin));
        } else {
            try!(req.reply(sock, origin));
        }
    }
    Ok(())
}

pub fn origin_member_list(req: &mut Envelope,
                          sock: &mut zmq::Socket,
                          state: &mut ServerState)
                          -> Result<()> {
    let msg: proto::OriginMemberListRequest = try!(req.parse_msg());
    let members = try!(state.datastore.origins.list_origin_members(msg.get_origin_id()));
    let mut r_members = RepeatedField::new();
    for member in members {
        r_members.push(member);
    }
    let mut resp = proto::OriginMemberListResponse::new();
    resp.set_origin_id(msg.get_origin_id());
    resp.set_members(r_members);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn account_origin_list(req: &mut Envelope,
                           sock: &mut zmq::Socket,
                           state: &mut ServerState)
                           -> Result<()> {
    let msg: proto::AccountOriginListRequest = try!(req.parse_msg());
    let origins = try!(state.datastore.origins.list_account_origins(msg.get_account_id()));
    let mut r_origins = RepeatedField::new();
    for origin in origins {
        r_origins.push(origin);
    }
    let mut resp = proto::AccountOriginListResponse::new();
    resp.set_account_id(msg.get_account_id());
    resp.set_origins(r_origins);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_secret_key_create(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginSecretKeyCreate = try!(req.parse_msg());
    let mut pk = proto::OriginSecretKey::new();
    pk.set_name(msg.get_name().to_string());
    pk.set_revision(msg.get_revision().to_string());
    pk.set_origin_id(msg.get_origin_id());
    pk.set_owner_id(msg.get_owner_id());
    pk.set_body(msg.get_body().to_vec());
    match state.datastore.origins.origin_secret_keys.write(&mut pk) {
        Ok(true) => try!(req.reply_complete(sock, &pk)),
        Ok(false) => {
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-secret-key-create:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("OriginSecretKeyCreate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:origin-secret-key-create:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn origin_secret_key_get(req: &mut Envelope,
                             sock: &mut zmq::Socket,
                             state: &mut ServerState)
                             -> Result<()> {
    let mut msg: proto::OriginSecretKeyGet = try!(req.parse_msg());
    match state.datastore.origins.key_idx.find(&msg.take_origin()) {
        Ok(ref id) => {
            let key = state.datastore.origins.origin_secret_keys.find(id).unwrap();
            try!(req.reply_complete(sock, &key));
        }
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:origin-secret-key-get:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("OriginSecretKeyGet, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:origin-secret-key-get:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_create(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let mut project = try!(req.parse_msg::<proto::ProjectCreate>()).take_project();
    match state.datastore.projects.write(&mut project) {
        Ok(true) => try!(req.reply_complete(sock, &project)),
        Ok(false) => {
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:project-create:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectCreate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-create:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_delete(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let mut msg: proto::ProjectDelete = try!(req.parse_msg());
    try!(state.datastore.projects.delete(&msg.take_id()));
    try!(req.reply_complete(sock, &NetOk::new()));
    Ok(())
}

pub fn project_get(req: &mut Envelope,
                   sock: &mut zmq::Socket,
                   state: &mut ServerState)
                   -> Result<()> {
    let mut msg: proto::ProjectGet = try!(req.parse_msg());
    match state.datastore.projects.find(&msg.take_id()) {
        Ok(ref project) => try!(req.reply_complete(sock, project)),
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:project-get:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectGet, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-get:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_update(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let msg: proto::ProjectUpdate = try!(req.parse_msg());
    match state.datastore.projects.update(&msg.get_project()) {
        Ok(()) => try!(req.reply_complete(sock, &NetOk::new())),
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:project-update:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectUpdate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-update:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}
<commit_msg>Ensure the requestor is a member of the origin, not the person invited.<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use dbcache::{self, BasicSet, IndexSet, InstaSet};
use hab_net::server::Envelope;
use protobuf::RepeatedField;
use protocol::net::{self, NetOk, ErrCode};
use protocol::vault as proto;
use zmq;

use super::ServerState;
use error::Result;

pub fn account_invitation_list(req: &mut Envelope,
                               sock: &mut zmq::Socket,
                               state: &mut ServerState)
                               -> Result<()> {
    let msg: proto::AccountInvitationListRequest = try!(req.parse_msg());
    let invites = try!(state.datastore.origins.invites.get_by_account_id(msg.get_account_id()));
    debug!("Got invites for account {} ", &msg.get_account_id());
    let mut resp = proto::AccountInvitationListResponse::new();
    resp.set_account_id(msg.get_account_id());

    let mut r_invites = RepeatedField::new();
    for invite in invites {
        r_invites.push(invite);
    }
    resp.set_invitations(r_invites);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_check_access(req: &mut Envelope,
                           sock: &mut zmq::Socket,
                           state: &mut ServerState)
                           -> Result<()> {
    let msg: proto::CheckOriginAccessRequest = try!(req.parse_msg());
    let is_member = try!(state.datastore
        .origins
        .is_origin_member(msg.get_account_id(), msg.get_origin_name()));
    let mut resp = proto::CheckOriginAccessResponse::new();
    resp.set_has_access(is_member);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_create(req: &mut Envelope,
                     sock: &mut zmq::Socket,
                     state: &mut ServerState)
                     -> Result<()> {
    let msg: proto::OriginCreate = try!(req.parse_msg());
    let mut origin = proto::Origin::new();
    origin.set_name(msg.get_name().to_string());
    origin.set_owner_id(msg.get_owner_id());
    if let Ok(_origin) = state.datastore
        .origins
        .name_idx
        .find(&msg.get_name().to_string()) {
        let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-create:0");
        try!(req.reply_complete(sock, &err));
    }
    try!(state.datastore.origins.write(&mut origin));
    debug!("Adding owner as origin member: {}", &msg.get_owner_name());
    try!(state.datastore
        .origins
        .add_origin_member(msg.get_owner_id(), msg.get_owner_name(), msg.get_name()));
    try!(req.reply_complete(sock, &origin));
    Ok(())
}

pub fn origin_get(req: &mut Envelope,
                  sock: &mut zmq::Socket,
                  state: &mut ServerState)
                  -> Result<()> {
    let mut msg: proto::OriginGet = try!(req.parse_msg());
    match state.datastore.origins.name_idx.find(&msg.take_name()) {
        Ok(origin_id) => {
            let mut origin = state.datastore.origins.find(&origin_id).unwrap();

            match state.datastore.origins.key_idx.find(&origin.get_name().to_string()) {
                Ok(key_id) => {
                    let secret_key =
                        state.datastore.origins.origin_secret_keys.find(&key_id).unwrap();
                    origin.set_private_key_name(format!("{}-{}",
                                                        secret_key.get_name(),
                                                        secret_key.get_revision()));
                }
                Err(e) => debug!("error looking for secret key {:?}", e),
            };

            try!(req.reply_complete(sock, &origin));
        }
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:origin-get:1");
            try!(req.reply_complete(sock, &err));
        }
        Err(e) => {
            error!("OriginGet, err={:?}", e);
            let err = net::err(ErrCode::BUG, "vt:origin-get:0");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn origin_invitation_accept(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginInvitationAcceptRequest = try!(req.parse_msg());
    match state.datastore.origins.invites.find(&msg.get_invite_id()) {
        Ok(invite) => {
            debug!("REQ    {:?}", &msg);
            debug!("INVITE {:?}", &invite);
            if msg.get_account_accepting_request() != invite.get_account_id() {
                let err = net::err(ErrCode::ACCESS_DENIED, "vt:origin-invite-accept:0");
                try!(req.reply_complete(sock, &err));
            }

            match state.datastore.origins.modify_invite(&invite, msg.get_ignore()) {
                Ok(()) => (),
                Err(e) => {
                    debug!("Error accepting invite: {}", e);
                }
            };
        }
        Err(e) => {
            debug!("Error accepting invite, maybe it's already been accepted? {}",
                   e);
        }
    };

    let resp = proto::OriginInvitationAcceptResponse::new();
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_invitation_create(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginInvitationCreate = try!(req.parse_msg());
    let mut invitation = proto::OriginInvitation::new();
    if !try!(state.datastore
        .origins
        .is_origin_member(msg.get_owner_id(), msg.get_origin_name())) {
        debug!("Can't invite to this org unless your already a member");
        let err = net::err(ErrCode::ACCESS_DENIED, "vt:origin-create:0");
        try!(req.reply_complete(sock, &err));
    }

    let existing_invites =
        try!(state.datastore.origins.invites.get_by_account_id(msg.get_account_id()));

    for invite in &existing_invites {
        if invite.get_origin_name() == msg.get_origin_name() {
            debug!("Invite for origin {} for user {} already exists",
                   &msg.get_origin_name(),
                   &msg.get_account_name());
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-create:1");
            try!(req.reply_complete(sock, &err));
            return Ok(());
        }
    }

    invitation.set_account_id(msg.get_account_id());
    invitation.set_account_name(msg.get_account_name().to_string());
    invitation.set_origin_id(msg.get_origin_id());
    invitation.set_origin_name(msg.get_origin_name().to_string());
    invitation.set_owner_id(msg.get_owner_id());

    try!(state.datastore.origins.invites.write(&mut invitation));
    try!(req.reply_complete(sock, &invitation));
    Ok(())
}

pub fn origin_invitation_list(req: &mut Envelope,
                              sock: &mut zmq::Socket,
                              state: &mut ServerState)
                              -> Result<()> {
    let msg: proto::OriginInvitationListRequest = try!(req.parse_msg());
    let invites = try!(state.datastore
        .origins
        .invites
        .get_by_origin_id(msg.get_origin_id()));
    let mut resp = proto::OriginInvitationListResponse::new();
    resp.set_origin_id(msg.get_origin_id());
    let mut r_invites = RepeatedField::new();
    for invite in invites {
        r_invites.push(invite);
    }
    resp.set_invitations(r_invites);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_list(req: &mut Envelope,
                   sock: &mut zmq::Socket,
                   _state: &mut ServerState)
                   -> Result<()> {
    let origin1 = proto::Origin::new();
    let origin2 = proto::Origin::new();
    let origins = vec![origin1, origin2];
    for (i, origin) in origins.iter().enumerate() {
        if i == origins.len() {
            try!(req.reply_complete(sock, origin));
        } else {
            try!(req.reply(sock, origin));
        }
    }
    Ok(())
}

pub fn origin_member_list(req: &mut Envelope,
                          sock: &mut zmq::Socket,
                          state: &mut ServerState)
                          -> Result<()> {
    let msg: proto::OriginMemberListRequest = try!(req.parse_msg());
    let members = try!(state.datastore.origins.list_origin_members(msg.get_origin_id()));
    let mut r_members = RepeatedField::new();
    for member in members {
        r_members.push(member);
    }
    let mut resp = proto::OriginMemberListResponse::new();
    resp.set_origin_id(msg.get_origin_id());
    resp.set_members(r_members);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn account_origin_list(req: &mut Envelope,
                           sock: &mut zmq::Socket,
                           state: &mut ServerState)
                           -> Result<()> {
    let msg: proto::AccountOriginListRequest = try!(req.parse_msg());
    let origins = try!(state.datastore.origins.list_account_origins(msg.get_account_id()));
    let mut r_origins = RepeatedField::new();
    for origin in origins {
        r_origins.push(origin);
    }
    let mut resp = proto::AccountOriginListResponse::new();
    resp.set_account_id(msg.get_account_id());
    resp.set_origins(r_origins);
    try!(req.reply_complete(sock, &resp));
    Ok(())
}

pub fn origin_secret_key_create(req: &mut Envelope,
                                sock: &mut zmq::Socket,
                                state: &mut ServerState)
                                -> Result<()> {
    let msg: proto::OriginSecretKeyCreate = try!(req.parse_msg());
    let mut pk = proto::OriginSecretKey::new();
    pk.set_name(msg.get_name().to_string());
    pk.set_revision(msg.get_revision().to_string());
    pk.set_origin_id(msg.get_origin_id());
    pk.set_owner_id(msg.get_owner_id());
    pk.set_body(msg.get_body().to_vec());
    match state.datastore.origins.origin_secret_keys.write(&mut pk) {
        Ok(true) => try!(req.reply_complete(sock, &pk)),
        Ok(false) => {
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:origin-secret-key-create:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("OriginSecretKeyCreate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:origin-secret-key-create:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn origin_secret_key_get(req: &mut Envelope,
                             sock: &mut zmq::Socket,
                             state: &mut ServerState)
                             -> Result<()> {
    let mut msg: proto::OriginSecretKeyGet = try!(req.parse_msg());
    match state.datastore.origins.key_idx.find(&msg.take_origin()) {
        Ok(ref id) => {
            let key = state.datastore.origins.origin_secret_keys.find(id).unwrap();
            try!(req.reply_complete(sock, &key));
        }
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:origin-secret-key-get:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("OriginSecretKeyGet, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:origin-secret-key-get:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_create(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let mut project = try!(req.parse_msg::<proto::ProjectCreate>()).take_project();
    match state.datastore.projects.write(&mut project) {
        Ok(true) => try!(req.reply_complete(sock, &project)),
        Ok(false) => {
            let err = net::err(ErrCode::ENTITY_CONFLICT, "vt:project-create:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectCreate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-create:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_delete(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let mut msg: proto::ProjectDelete = try!(req.parse_msg());
    try!(state.datastore.projects.delete(&msg.take_id()));
    try!(req.reply_complete(sock, &NetOk::new()));
    Ok(())
}

pub fn project_get(req: &mut Envelope,
                   sock: &mut zmq::Socket,
                   state: &mut ServerState)
                   -> Result<()> {
    let mut msg: proto::ProjectGet = try!(req.parse_msg());
    match state.datastore.projects.find(&msg.take_id()) {
        Ok(ref project) => try!(req.reply_complete(sock, project)),
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:project-get:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectGet, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-get:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}

pub fn project_update(req: &mut Envelope,
                      sock: &mut zmq::Socket,
                      state: &mut ServerState)
                      -> Result<()> {
    let msg: proto::ProjectUpdate = try!(req.parse_msg());
    match state.datastore.projects.update(&msg.get_project()) {
        Ok(()) => try!(req.reply_complete(sock, &NetOk::new())),
        Err(dbcache::Error::EntityNotFound) => {
            let err = net::err(ErrCode::ENTITY_NOT_FOUND, "vt:project-update:0");
            try!(req.reply_complete(sock, &err));
        }
        Err(err) => {
            error!("ProjectUpdate, err={:?}", err);
            let err = net::err(ErrCode::DATA_STORE, "vt:project-update:1");
            try!(req.reply_complete(sock, &err));
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! General implementation of tdos base structure.
use json::parse;
use std::fs::File;
use std::io::Read;
use list::TodoList;
use todo::Todo;
use error::*;

/// Basic container structure for a set of todo lists.
///
/// This data structure acts as a conatiner for all todo lists and its associated todos.
/// The whole `tdo` microcosm settles around this structure
/// which is also used for (de-)serialization.
///
/// When instanciated, it comes with an empty _default_ list.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tdo {
    /// A vector of all todo lists.
    pub lists: Vec<TodoList>,
    /// The tdo version the last dump was saved with.
    version: String,
}

impl Tdo {
    /// Create a new `Tdo` container.
    /// Each new container is instanciated with a _default_ `TodoList`.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// let tdo = Tdo::new();
    /// ```
    pub fn new() -> Tdo {
        Tdo {
            lists: vec![TodoList::default()],
            version: env!("CARGO_PKG_VERSION").to_string(),
        }
    }

    /// Load a saved `Tdo` container from a JSON file.
    ///
    /// This function returns a `ResultType` which will yield the
    /// deserialized JSON or a `serde_json::Error`.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// let mut tdo = Tdo::load("foo.json");
    /// ```
    pub fn load(path: &str) -> TdoResult<Tdo> {
        match File::open(path) {
            Ok(file) => {
                match super::serde_json::from_reader(&file) {
                    Ok(tdo) => Ok(tdo),
                    Err(_) => update_json(path),
                }
            }
            Err(_) => Err(StorageError::FileNotFound.into()),
        }

    }

    /// Dump the `Tdo` container to a JSON file.
    ///
    /// This function returns a `ResultType` yielding a `StorageError::SaveFailure`
    /// if the JSON file could not be opened/saved.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// # let mut tdo = Tdo::new();
    /// let res = tdo.save("foo.json");
    /// assert_eq!(res.unwrap(), ());
    /// ```
    pub fn save(&self, path: &str) -> TdoResult<()> {
        // TODO: At this point we could be much more precise about the error if we would include
        // the error from the file system as SaveFailure(ArbitraryErrorFromFS)
        //  -- Feliix42 (2017-03-14; 17:04)
        match File::create(path) {
            Ok(mut f) => {
                let _ = super::serde_json::to_writer_pretty(&mut f, self);
                Ok(())
            }
            Err(_) => Err(StorageError::SaveFailure.into()),
        }
    }

    /// Add a todo list to the container.
    pub fn add_list(&mut self, list: TodoList) -> TdoResult<()> {
        match self.get_list_index(&list.name) {
            Ok(_) => Err(TodoError::NameAlreadyExists.into()),
            Err(_) => {
                self.lists.push(list);
                Ok(())
            }
        }
    }

    /// Removes a list from the container.
    pub fn remove_list(&mut self, list_name: &str) -> TdoResult<()> {
        if list_name == "default" {
            Err(TodoError::CanNotRemoveDefault.into())
        } else {
            match self.get_list_index(list_name) {
                Ok(index) => {
                    self.lists.remove(index);
                    Ok(())
                }
                Err(_) => Err(TodoError::NoSuchList.into()),
            }
        }
    }

    /// Add a todo to the todo list, identified by its name.
    ///
    /// This function returns a `ResultType` with a `TodoError::NoSuchList`
    /// if there is no matching list found.
    pub fn add_todo(&mut self, list_name: Option<&str>, todo: Todo) -> TdoResult<()> {
        match self.get_list_index(&list_name.unwrap_or("default")) {
            Ok(index) => {
                self.lists[index].add(todo);
                Ok(())
            }
            Err(x) => Err(x),
        }
    }

    /// Cycle through all todo lists and mark a todo with the given IDas done.
    /// This function has no return value and thus won't indicate whether
    /// there was a matching todo found.
    pub fn done_id(&mut self, id: u32) {
        for list in 0..self.lists.len() {
            let _ = self.lists[list].done_id(id);
        }
    }

    /// Cycle through all todo lists and remove a todo with the given id.
    /// This function has no return value and thus won't indicate whether
    /// there was a matching todo found.
    pub fn remove_id(&mut self, id: u32) {
        for list in self.to_owned().lists.into_iter() {
            let list_id = self.get_list_index(&list.name).unwrap();
            println!("{:?}", &list_id);
            if self.lists[list_id].remove_id(id).is_ok(){
                return
            }
        }
    }

    /// Remove all todos that have been marked as _done_ from all todo lists.
    pub fn clean_lists(&mut self) {
        for list in 0..self.lists.len() {
            self.lists[list].clean();
        }
    }

    fn get_list_index(&self, name: &str) -> TdoResult<usize> {
        match self.lists
            .iter()
            .position(|x| x.name.to_lowercase() == name.to_string().to_lowercase()) {
            Some(index) => Ok(index),
            None => Err(TodoError::NoSuchList.into()),
        }
    }

    /// Get the highest ID used in the tdo container.
    pub fn get_highest_id(&self) -> u32 {
        self.lists.iter().fold(0, |acc, &ref x| {
            x.list.iter().fold(acc, |inner_acc, &ref y| if inner_acc < y.id {y.id} else {inner_acc})
        })
    }
}

fn update_json(path: &str) -> TdoResult<Tdo> {
    let mut file = File::open(path).unwrap();
    let mut data = String::new();
    file.read_to_string(&mut data).unwrap();
    let mut json = match parse(&data) {
        Ok(content) => content,
        Err(_) => return Err(StorageError::FileCorrupted.into()),
    };

    let mut lists: Vec<TodoList> = vec![];

    for outer in json.entries_mut() {
        let mut list = TodoList::new(outer.0);
        for inner in outer.1.entries_mut() {
            let tdo_id = match inner.0.parse::<u32>() {
                Ok(id) => id,
                Err(_) => return Err(StorageError::UnableToConvert.into()),
            };
            let done = match inner.1.pop().as_bool() {
                Some(x) => x,
                None => return Err(StorageError::UnableToConvert.into()),
            };
            let tdo_name = match inner.1.pop().as_str() {
                Some(x) => String::from(x),
                None => return Err(StorageError::UnableToConvert.into()),
            };
            let mut todo = Todo::new(tdo_id, &tdo_name);
            if done {
                todo.set_done();
            }
            list.add(todo);
        }
        lists.push(list);
    }
    let tdo = Tdo {
        lists: lists,
        version: env!("CARGO_PKG_VERSION").to_string(),
    };
    Ok(tdo)
}
<commit_msg>remove debug print<commit_after>//! General implementation of tdos base structure.
use json::parse;
use std::fs::File;
use std::io::Read;
use list::TodoList;
use todo::Todo;
use error::*;

/// Basic container structure for a set of todo lists.
///
/// This data structure acts as a conatiner for all todo lists and its associated todos.
/// The whole `tdo` microcosm settles around this structure
/// which is also used for (de-)serialization.
///
/// When instanciated, it comes with an empty _default_ list.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tdo {
    /// A vector of all todo lists.
    pub lists: Vec<TodoList>,
    /// The tdo version the last dump was saved with.
    version: String,
}

impl Tdo {
    /// Create a new `Tdo` container.
    /// Each new container is instanciated with a _default_ `TodoList`.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// let tdo = Tdo::new();
    /// ```
    pub fn new() -> Tdo {
        Tdo {
            lists: vec![TodoList::default()],
            version: env!("CARGO_PKG_VERSION").to_string(),
        }
    }

    /// Load a saved `Tdo` container from a JSON file.
    ///
    /// This function returns a `ResultType` which will yield the
    /// deserialized JSON or a `serde_json::Error`.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// let mut tdo = Tdo::load("foo.json");
    /// ```
    pub fn load(path: &str) -> TdoResult<Tdo> {
        match File::open(path) {
            Ok(file) => {
                match super::serde_json::from_reader(&file) {
                    Ok(tdo) => Ok(tdo),
                    Err(_) => update_json(path),
                }
            }
            Err(_) => Err(StorageError::FileNotFound.into()),
        }

    }

    /// Dump the `Tdo` container to a JSON file.
    ///
    /// This function returns a `ResultType` yielding a `StorageError::SaveFailure`
    /// if the JSON file could not be opened/saved.
    ///
    /// # Example
    ///
    /// ```
    /// # use tdo_core::tdo::*;
    /// # let mut tdo = Tdo::new();
    /// let res = tdo.save("foo.json");
    /// assert_eq!(res.unwrap(), ());
    /// ```
    pub fn save(&self, path: &str) -> TdoResult<()> {
        // TODO: At this point we could be much more precise about the error if we would include
        // the error from the file system as SaveFailure(ArbitraryErrorFromFS)
        //  -- Feliix42 (2017-03-14; 17:04)
        match File::create(path) {
            Ok(mut f) => {
                let _ = super::serde_json::to_writer_pretty(&mut f, self);
                Ok(())
            }
            Err(_) => Err(StorageError::SaveFailure.into()),
        }
    }

    /// Add a todo list to the container.
    pub fn add_list(&mut self, list: TodoList) -> TdoResult<()> {
        match self.get_list_index(&list.name) {
            Ok(_) => Err(TodoError::NameAlreadyExists.into()),
            Err(_) => {
                self.lists.push(list);
                Ok(())
            }
        }
    }

    /// Removes a list from the container.
    pub fn remove_list(&mut self, list_name: &str) -> TdoResult<()> {
        if list_name == "default" {
            Err(TodoError::CanNotRemoveDefault.into())
        } else {
            match self.get_list_index(list_name) {
                Ok(index) => {
                    self.lists.remove(index);
                    Ok(())
                }
                Err(_) => Err(TodoError::NoSuchList.into()),
            }
        }
    }

    /// Add a todo to the todo list, identified by its name.
    ///
    /// This function returns a `ResultType` with a `TodoError::NoSuchList`
    /// if there is no matching list found.
    pub fn add_todo(&mut self, list_name: Option<&str>, todo: Todo) -> TdoResult<()> {
        match self.get_list_index(&list_name.unwrap_or("default")) {
            Ok(index) => {
                self.lists[index].add(todo);
                Ok(())
            }
            Err(x) => Err(x),
        }
    }

    /// Cycle through all todo lists and mark a todo with the given IDas done.
    /// This function has no return value and thus won't indicate whether
    /// there was a matching todo found.
    pub fn done_id(&mut self, id: u32) {
        for list in 0..self.lists.len() {
            let _ = self.lists[list].done_id(id);
        }
    }

    /// Cycle through all todo lists and remove a todo with the given id.
    /// This function has no return value and thus won't indicate whether
    /// there was a matching todo found.
    pub fn remove_id(&mut self, id: u32) {
        for list in self.to_owned().lists.into_iter() {
            let list_id = self.get_list_index(&list.name).unwrap();
            if self.lists[list_id].remove_id(id).is_ok(){
                return
            }
        }
    }

    /// Remove all todos that have been marked as _done_ from all todo lists.
    pub fn clean_lists(&mut self) {
        for list in 0..self.lists.len() {
            self.lists[list].clean();
        }
    }

    fn get_list_index(&self, name: &str) -> TdoResult<usize> {
        match self.lists
            .iter()
            .position(|x| x.name.to_lowercase() == name.to_string().to_lowercase()) {
            Some(index) => Ok(index),
            None => Err(TodoError::NoSuchList.into()),
        }
    }

    /// Get the highest ID used in the tdo container.
    pub fn get_highest_id(&self) -> u32 {
        self.lists.iter().fold(0, |acc, &ref x| {
            x.list.iter().fold(acc, |inner_acc, &ref y| if inner_acc < y.id {y.id} else {inner_acc})
        })
    }
}

fn update_json(path: &str) -> TdoResult<Tdo> {
    let mut file = File::open(path).unwrap();
    let mut data = String::new();
    file.read_to_string(&mut data).unwrap();
    let mut json = match parse(&data) {
        Ok(content) => content,
        Err(_) => return Err(StorageError::FileCorrupted.into()),
    };

    let mut lists: Vec<TodoList> = vec![];

    for outer in json.entries_mut() {
        let mut list = TodoList::new(outer.0);
        for inner in outer.1.entries_mut() {
            let tdo_id = match inner.0.parse::<u32>() {
                Ok(id) => id,
                Err(_) => return Err(StorageError::UnableToConvert.into()),
            };
            let done = match inner.1.pop().as_bool() {
                Some(x) => x,
                None => return Err(StorageError::UnableToConvert.into()),
            };
            let tdo_name = match inner.1.pop().as_str() {
                Some(x) => String::from(x),
                None => return Err(StorageError::UnableToConvert.into()),
            };
            let mut todo = Todo::new(tdo_id, &tdo_name);
            if done {
                todo.set_done();
            }
            list.add(todo);
        }
        lists.push(list);
    }
    let tdo = Tdo {
        lists: lists,
        version: env!("CARGO_PKG_VERSION").to_string(),
    };
    Ok(tdo)
}
<|endoftext|>


<commit_before>use std::{fs, io};
use std::os::unix::io::AsRawFd;

/// Is this stream an TTY?
#[cfg(not(target_os = "redox"))]
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
    use libc;

    unsafe { libc::isatty(stream.as_raw_fd()) == 1 }
}

/// This will panic.
#[cfg(target_os = "redox")]
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
    use syscall;

    if let Ok(fd) = syscall::dup(stream.as_raw_fd(), b"termios") {
        let _ = syscall::close(fd);
        true
    } else {
        false
    }
}

/// Get the TTY device.
///
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
#[cfg(target_os = "redox")]
pub fn get_tty() -> io::Result<fs::File> {
    use std::env;
    let tty = try!(env::var("TTY").map_err(|x| io::Error::new(io::ErrorKind::NotFound, x)));
    fs::OpenOptions::new().read(true).write(true).open(tty)
}

/// Get the TTY device.
///
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
#[cfg(not(target_os = "redox"))]
pub fn get_tty() -> io::Result<fs::File> {
    fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
}
<commit_msg>Update tty.rs<commit_after>use std::{fs, io};
use std::os::unix::io::AsRawFd;

/// Is this stream a TTY?
#[cfg(not(target_os = "redox"))]
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
    use libc;

    unsafe { libc::isatty(stream.as_raw_fd()) == 1 }
}

/// Is this stream a TTY?
#[cfg(target_os = "redox")]
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
    use syscall;

    if let Ok(fd) = syscall::dup(stream.as_raw_fd(), b"termios") {
        let _ = syscall::close(fd);
        true
    } else {
        false
    }
}

/// Get the TTY device.
///
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
#[cfg(target_os = "redox")]
pub fn get_tty() -> io::Result<fs::File> {
    use std::env;
    let tty = try!(env::var("TTY").map_err(|x| io::Error::new(io::ErrorKind::NotFound, x)));
    fs::OpenOptions::new().read(true).write(true).open(tty)
}

/// Get the TTY device.
///
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
#[cfg(not(target_os = "redox"))]
pub fn get_tty() -> io::Result<fs::File> {
    fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
}
<|endoftext|>