<commit_before>use packet::InnerStmt;
use std::borrow::Borrow;
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::IntoIter;
#[cfg(test)]
use std::collections::vec_deque::Iter;
use std::hash::{BuildHasherDefault, Hash};
use twox_hash::XxHash;

#[derive(Debug)]
pub struct StmtCache {
    cap: usize,
    map: HashMap<String, InnerStmt, BuildHasherDefault<XxHash>>,
    order: VecDeque<String>,
}

impl StmtCache {
    pub fn new(cap: usize) -> StmtCache {
        StmtCache {
            cap,
            map: Default::default(),
            order: VecDeque::with_capacity(cap),
        }
    }

    pub fn contains<T>(&self, key: &T) -> bool
        where String: Borrow<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        self.map.contains_key(key)
    }

    pub fn get<T>(&mut self, key: &T) -> Option<&InnerStmt>
        where String: Borrow<T>,
              String: PartialEq<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        if self.map.contains_key(key) {
            if let Some(mut pos) = self.order.iter().position(|x| x == key) {
                while pos < self.order.len() - 1 {
                    self.order.swap(pos, pos + 1);
                    pos += 1;
                }
            }
            self.map.get(key)
        } else {
            None
        }
    }

    pub fn put(&mut self, key: String, value: InnerStmt) -> Option<InnerStmt> {
        self.map.insert(key.clone(), value);
        self.order.push_back(key);
        if self.order.len() > self.cap {
            self.order.pop_front().and_then(|stmt| self.map.remove(&stmt))
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.order.clear();
    }

    #[cfg(test)]
    pub fn iter<'a>(&'a self) -> Iter<'a, String> {
        self.order.iter()
    }

    pub fn into_iter(self) -> IntoIter<String, InnerStmt> {
        self.map.into_iter()
    }

    pub fn get_cap(&self) -> usize {
        self.cap
    }
}<commit_msg>StmtCache: use VecDeque::{remove, push_back} instead of manual reorder.<commit_after>use packet::InnerStmt;
use std::borrow::Borrow;
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::IntoIter;
#[cfg(test)]
use std::collections::vec_deque::Iter;
use std::hash::{BuildHasherDefault, Hash};
use twox_hash::XxHash;

#[derive(Debug)]
pub struct StmtCache {
    cap: usize,
    map: HashMap<String, InnerStmt, BuildHasherDefault<XxHash>>,
    order: VecDeque<String>,
}

impl StmtCache {
    pub fn new(cap: usize) -> StmtCache {
        StmtCache {
            cap,
            map: Default::default(),
            order: VecDeque::with_capacity(cap),
        }
    }

    pub fn contains<T>(&self, key: &T) -> bool
        where String: Borrow<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        self.map.contains_key(key)
    }

    pub fn get<T>(&mut self, key: &T) -> Option<&InnerStmt>
        where String: Borrow<T>,
              String: PartialEq<T>,
              T: Hash + Eq,
              T: ?Sized
    {
        if self.map.contains_key(key) {
            if let Some(pos) = self.order.iter().position(|x| x == key) {
                if let Some(inner_st) = self.order.remove(pos) {
                    self.order.push_back(inner_st);
                }
            }
            self.map.get(key)
        } else {
            None
        }
    }

    pub fn put(&mut self, key: String, value: InnerStmt) -> Option<InnerStmt> {
        self.map.insert(key.clone(), value);
        self.order.push_back(key);
        if self.order.len() > self.cap {
            self.order.pop_front().and_then(|stmt| self.map.remove(&stmt))
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        self.map.clear();
        self.order.clear();
    }

    #[cfg(test)]
    pub fn iter<'a>(&'a self) -> Iter<'a, String> {
        self.order.iter()
    }

    pub fn into_iter(self) -> IntoIter<String, InnerStmt> {
        self.map.into_iter()
    }

    pub fn get_cap(&self) -> usize {
        self.cap
    }
}<|endoftext|>


<commit_before>//! Provides the generics and interfaces for the specific Solvers.
//!
//! See [Solvers][solvers]
//! [solvers]: ../solvers/index.html

pub mod confusion_matrix;

pub use self::confusion_matrix::ConfusionMatrix;

use std::rc::Rc;
use std::marker::PhantomData;
use co::prelude::*;
use layer::*;
use layers::SequentialConfig;
use solvers::*;
use util::{ArcLock, LayerOps, SolverOps};

#[derive(Debug)]
/// Solver that optimizes a [Layer][1] with a given objective.
/// [1]: ../layer/index.html
pub struct Solver<SolverB: IBackend + SolverOps<f32>, B: IBackend + LayerOps<f32>> {
    net: Layer<B>,
    objective: Layer<SolverB>,
    /// The implementation of the Solver
    pub worker: Box<ISolver<SolverB, B>>,

    config: SolverConfig,

    /// The current iteration / number of times weights have been updated
    iter: usize,

    solver_backend: PhantomData<SolverB>,
}

impl<SolverB: IBackend + SolverOps<f32> + 'static, B: IBackend + LayerOps<f32> + 'static> Solver<SolverB, B> {
    /// Create Solver from [SolverConfig][1]
    /// [1]: ./struct.SolverConfig.html
    ///
    /// This is the **preferred method** to create a Solver for training a neural network.
    pub fn from_config(net_backend: Rc<B>, obj_backend: Rc<SolverB>, config: &SolverConfig) -> Solver<SolverB, B> {
        let network = Layer::from_config(net_backend, &config.network);
        let mut worker = config.solver.with_config(obj_backend.clone(), &config);
        worker.init(&network);

        Solver {
            worker: worker,
            net: network,
            objective: Layer::from_config(obj_backend, &config.objective),
            iter: 0,

            config: config.clone(),
            solver_backend: PhantomData::<SolverB>,
        }
    }

}

impl<SolverB: IBackend + SolverOps<f32> + 'static, B: IBackend + LayerOps<f32> + 'static> Solver<SolverB, B>{
    fn init(&mut self, backend: Rc<B>) {
        info!("Initializing solver from configuration");

        let mut config = self.config.clone();
        self.init_net(backend, &mut config);
    }

    /// Initialize the training net
    fn init_net(&mut self, backend: Rc<B>, param: &mut SolverConfig) {
        self.net = Layer::from_config(backend, &param.network);
    }

    /// Train the network with one minibatch
    pub fn train_minibatch(&mut self, mb_data: ArcLock<SharedTensor<f32>>, mb_target: ArcLock<SharedTensor<f32>>) -> ArcLock<SharedTensor<f32>> {
        self.net.clear_weights_gradients();

        // forward through network and classifier
        let network_out = self.net.forward(&[mb_data])[0].clone();
        let _ = self.objective.forward(&[network_out.clone(), mb_target]);

        // forward through network and classifier
        let classifier_gradient = self.objective.backward(&[]);
        self.net.backward(&classifier_gradient[0 .. 1]);

        self.worker.compute_update(&self.config, &mut self.net, self.iter);
        self.net.update_weights(self.worker.backend());
        self.iter += 1;

        network_out
    }

    /// Returns the network trained by the solver.
    ///
    /// This is the recommended method to get a usable trained network.
    pub fn network(&self) -> &Layer<B> {
        &self.net
    }

    /// Returns the network trained by the solver.
    ///
    /// This is the recommended method to get a trained network,
    /// if you want to alter the network. Keep in mind that altering the network
    /// might render the solver unusable and continuing training the network with it will yield
    /// unexpected results.
    pub fn mut_network(&mut self) -> &mut Layer<B> {
        &mut self.net
    }
}

/// Implementation of a specific Solver.
///
/// See [Solvers][1]
/// [1]: ../solvers/index.html
pub trait ISolver<SolverB, B: IBackend + LayerOps<f32>> {
    /// Initialize the solver, setting up any network related data.
    fn init(&mut self, net: &Layer<B>) {}

    /// Update the weights of the net with part of the gradient.
    ///
    /// The [second phase of backpropagation learning][1].
    /// Calculates the gradient update that should be applied to the network,
    /// and then applies that gradient to the network, changing its weights.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Backpropagation#Phase_2:_Weight_update
    ///
    /// Used by [step][2] to optimize the network.
    ///
    /// [2]: ./struct.Solver.html#method.step
    fn compute_update(&mut self, param: &SolverConfig, network: &mut Layer<B>, iter: usize);

    /// Returns the backend used by the solver.
    fn backend(&self) -> &SolverB;
}

impl<SolverB, B: IBackend + LayerOps<f32>> ::std::fmt::Debug for ISolver<SolverB, B> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "({})", "ILayer")
    }
}

#[derive(Debug, Clone)]
/// Configuration for a Solver
pub struct SolverConfig {
    /// Name of the solver.
    pub name: String,
    /// The [LayerConfig][1] that is used to initialize the network.
    /// [1]: ../layer/struct.LayerConfig.html
    pub network: LayerConfig,
    /// The [LayerConfig][1] that is used to initialize the objective.
    /// [1]: ../layer/struct.LayerConfig.html
    pub objective: LayerConfig,
    /// The [Solver implementation][1] to be used.
    /// [1]: ../solvers/index.html
    pub solver: SolverKind,
    /// Accumulate gradients over `minibatch_size` instances.
    ///
    /// Default: 1
    pub minibatch_size: usize,
    /// The learning rate policy to be used.
    ///
    /// Default: Fixed
    pub lr_policy: LRPolicy,
    /// The base learning rate.
    ///
    /// Default: 0.01
    pub base_lr: f32,
    /// gamma as used in the calculation of most learning rate policies.
    ///
    /// Default: 0.1
    pub gamma: f32,
    /// The stepsize used in Step and Sigmoid learning policies.
    ///
    /// Default: 10
    pub stepsize: usize,
    /// The threshold for clipping gradients.
    ///
    /// Gradient values will be scaled to their [L2 norm][1] of length `clip_gradients`
    /// if their L2 norm is larger than `clip_gradients`.
    /// If set to `None` gradients will not be clipped.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm
    ///
    /// Default: None
    pub clip_gradients: Option<f32>,
    /// The global [weight decay][1] multiplier for [regularization][2].
    /// [1]: http://www.alglib.net/dataanalysis/improvinggeneralization.php#header3
    /// [2]: https://cs231n.github.io/neural-networks-2/#reg
    ///
    /// Regularization can prevent [overfitting][3].
    ///
    /// If set to `None` no regularization will be performed.
    ///
    /// [3]: https://cs231n.github.io/neural-networks-2/#reg
    pub weight_decay: Option<f32>,
    /// The method of [regularization][1] to use.
    /// [1]: https://cs231n.github.io/neural-networks-2/#reg
    ///
    /// There are different methods for regularization.
    /// The two most common ones are [L1 regularization][1] and [L2 regularization][1].
    ///
    /// See [RegularizationMethod][2] for all implemented methods.
    ///
    /// [2]: ./enum.RegularizationMethod.html
    ///
    /// Currently only L2 regularization is implemented.
    /// See [Issue #23](https://github.com/autumnai/leaf/issues/23).
    pub regularization_method: Option<RegularizationMethod>,
    /// The [momentum][1] multiplier for [SGD solvers][2].
    /// [1]: https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Momentum
    /// [2]: ../solvers/sgd/index.html
    ///
    /// For more information see [SGD with momentum][3]
    /// [3]: ../solvers/sgd/momentum/index.html
    ///
    /// The value should always be between 0 and 1 and dictates how much of the previous
    /// gradient update will be added to the current one.
    ///
    /// Default: 0
    pub momentum: f32,
}

impl Default for SolverConfig {
    fn default() -> SolverConfig {
        SolverConfig {
            name: "".to_owned(),
            network: LayerConfig::new("default", SequentialConfig::default()),
            objective: LayerConfig::new("default", SequentialConfig::default()),
            solver: SolverKind::SGD(SGDKind::Momentum),

            minibatch_size: 1,

            lr_policy: LRPolicy::Fixed,
            base_lr: 0.01f32,
            gamma: 0.1f32,
            stepsize: 10,

            clip_gradients: None,

            weight_decay: None,
            regularization_method: None,

            momentum: 0f32,
        }
    }
}

impl SolverConfig {
    /// Return the learning rate for a supplied iteration.
    ///
    /// The way the learning rate is calculated depends on the configured [LRPolicy][1].
    ///
    /// [1]: ./enum.LRPolicy.html
    ///
    /// Used by the [Solver][2] to calculate the learning rate for the current iteration.
    /// The calculated learning rate has a different effect on training dependent on what
    /// [type of Solver][3] you are using.
    ///
    /// [2]: ./struct.Solver.html
    /// [3]: ../solvers/index.html
    pub fn get_learning_rate(&self, iter: usize) -> f32 {
        match self.lr_policy() {
            LRPolicy::Fixed => {
                self.base_lr()
            }
            LRPolicy::Step => {
                let current_step = self.step(iter);
                self.base_lr() * self.gamma().powf(current_step as f32)
            }
            // LRPolicy::Multistep => {
            //     // TODO: the current step can be calculated on-demand
            //     //   if (this->current_step_ < this->param_.stepvalue_size() &&
            //     //         this->iter_ >= this->param_.stepvalue(this->current_step_)) {
            //     //     this->current_step_++;
            //     //     LOG(INFO) << "MultiStep Status: Iteration " <<
            //     //     this->iter_ << ", step = " << this->current_step_;
            //     //   }
            //     //   rate = this->param_.base_lr() *
            //     //       pow(this->param_.gamma(), this->current_step_);
            //     unimplemented!();
            // }
            LRPolicy::Exp => {
                self.base_lr() * self.gamma().powf(iter as f32)
            }
            // LRPolicy::Inv => {
            //     //   rate = this->param_.base_lr() *
            //     //       pow(Dtype(1) + this->param_.gamma() * this->iter_,
            //     //           - this->param_.power());
            //     unimplemented!();
            // }
            // LRPolicy::Poly => {
            //     //   rate = this->param_.base_lr() * pow(Dtype(1.) -
            //     //       (Dtype(this->iter_) / Dtype(this->param_.max_iter())),
            //     //       this->param_.power());
            //     unimplemented!();
            // }
            // LRPolicy::Sigmoid => {
            //     //   rate = this->param_.base_lr() * (Dtype(1.) /
            //     //       (Dtype(1.) + exp(-this->param_.gamma() * (Dtype(this->iter_) -
            //     //         Dtype(this->param_.stepsize())))));
            //     unimplemented!();
            // }
        }
    }

    /// Return current step at iteration `iter`.
    ///
    /// Small helper for learning rate calculation.
    fn step(&self, iter: usize) -> usize {
        iter / self.stepsize()
    }

    /// Return learning rate policy.
    fn lr_policy(&self) -> LRPolicy {
        self.lr_policy
    }

    /// Return the base learning rate.
    fn base_lr(&self) -> f32 {
        self.base_lr
    }

    /// Return the gamma for learning rate calculations.
    fn gamma(&self) -> f32 {
        self.gamma
    }

    /// Return the stepsize for learning rate calculations.
    fn stepsize(&self) -> usize {
        self.stepsize
    }
}

#[derive(Debug, Copy, Clone)]
/// All available types of solvers.
pub enum SolverKind {
    /// Stochastic Gradient Descent.
    /// See [SGDKind][1] for all available SGD solvers.
    /// [1]: ./enum.SGDKind.html
    SGD(SGDKind),
}

impl SolverKind {
    /// Create a Solver of the specified kind with the supplied SolverConfig.
    pub fn with_config<B: IBackend + SolverOps<f32> + 'static, NetB: IBackend + LayerOps<f32> + 'static>(&self, backend: Rc<B>, config: &SolverConfig) -> Box<ISolver<B, NetB>> {
        match *self {
            SolverKind::SGD(sgd) => {
                sgd.with_config(backend, config)
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// All available types of Stochastic Gradient Descent solvers.
pub enum SGDKind {
    /// Stochastic Gradient Descent with Momentum. See [implementation][1]
    /// [1] ../solvers/
    Momentum,
}

impl SGDKind {
    /// Create a Solver of the specified kind with the supplied SolverConfig.
    pub fn with_config<B: IBackend + SolverOps<f32> + 'static, NetB: IBackend + LayerOps<f32> + 'static>(&self, backend: Rc<B>, config: &SolverConfig) -> Box<ISolver<B, NetB>> {
        match *self {
            SGDKind::Momentum => {
                Box::new(Momentum::<B>::new(backend))
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// Learning Rate Policy for a [Solver][1]
/// [1]: ./struct.Solver.html
///
/// The variables mentioned below are defined in the [SolverConfig][2] apart from
/// iter, which is the current iteration of the solver, that is supplied as a parameter
/// for the learning rate calculation.
///
/// [2]: ./struct.SolverConfig.html
pub enum LRPolicy {
    /// always return base_lr
    Fixed,
    /// learning rate decays every `step` iterations.
    /// return base_lr * gamma ^ (floor(iter / step))
    Step,
    // /// similar to step but it allows non uniform steps defined by
    // /// stepvalue
    // Multistep,
    /// return base_lr * gamma ^ iter
    Exp,
    // /// return base_lr * (1 + gamma * iter) ^ (- power)
    // Inv,
    // /// the effective learning rate follows a polynomial decay, to be
    // /// zero by the max_iter.
    // /// return base_lr (1 - iter/max_iter) ^ (power)
    // Poly,
    // /// the effective learning rate follows a sigmod decay
    // /// return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
    // Sigmoid,
}

#[derive(Debug, Copy, Clone)]
/// [Regularization][1] method for a [Solver][2].
/// [1]: https://cs231n.github.io/neural-networks-2/#reg
/// [2]: ./struct.Solver.html
pub enum RegularizationMethod {
    /// L2 regularization
    L2,
}
<commit_msg>Auto merge of #90 - alexandermorozov:solver-rm-zerofill, r=hobofan<commit_after>//! Provides the generics and interfaces for the specific Solvers.
//!
//! See [Solvers][solvers]
//! [solvers]: ../solvers/index.html

pub mod confusion_matrix;

pub use self::confusion_matrix::ConfusionMatrix;

use std::rc::Rc;
use std::marker::PhantomData;
use co::prelude::*;
use layer::*;
use layers::SequentialConfig;
use solvers::*;
use util::{ArcLock, LayerOps, SolverOps};

#[derive(Debug)]
/// Solver that optimizes a [Layer][1] with a given objective.
/// [1]: ../layer/index.html
pub struct Solver<SolverB: IBackend + SolverOps<f32>, B: IBackend + LayerOps<f32>> {
    net: Layer<B>,
    objective: Layer<SolverB>,
    /// The implementation of the Solver
    pub worker: Box<ISolver<SolverB, B>>,

    config: SolverConfig,

    /// The current iteration / number of times weights have been updated
    iter: usize,

    solver_backend: PhantomData<SolverB>,
}

impl<SolverB: IBackend + SolverOps<f32> + 'static, B: IBackend + LayerOps<f32> + 'static> Solver<SolverB, B> {
    /// Create Solver from [SolverConfig][1]
    /// [1]: ./struct.SolverConfig.html
    ///
    /// This is the **preferred method** to create a Solver for training a neural network.
    pub fn from_config(net_backend: Rc<B>, obj_backend: Rc<SolverB>, config: &SolverConfig) -> Solver<SolverB, B> {
        let network = Layer::from_config(net_backend, &config.network);
        let mut worker = config.solver.with_config(obj_backend.clone(), &config);
        worker.init(&network);

        Solver {
            worker: worker,
            net: network,
            objective: Layer::from_config(obj_backend, &config.objective),
            iter: 0,

            config: config.clone(),
            solver_backend: PhantomData::<SolverB>,
        }
    }

}

impl<SolverB: IBackend + SolverOps<f32> + 'static, B: IBackend + LayerOps<f32> + 'static> Solver<SolverB, B>{
    fn init(&mut self, backend: Rc<B>) {
        info!("Initializing solver from configuration");

        let mut config = self.config.clone();
        self.init_net(backend, &mut config);
    }

    /// Initialize the training net
    fn init_net(&mut self, backend: Rc<B>, param: &mut SolverConfig) {
        self.net = Layer::from_config(backend, &param.network);
    }

    /// Train the network with one minibatch
    pub fn train_minibatch(&mut self, mb_data: ArcLock<SharedTensor<f32>>, mb_target: ArcLock<SharedTensor<f32>>) -> ArcLock<SharedTensor<f32>> {
        // forward through network and classifier
        let network_out = self.net.forward(&[mb_data])[0].clone();
        let _ = self.objective.forward(&[network_out.clone(), mb_target]);

        // forward through network and classifier
        let classifier_gradient = self.objective.backward(&[]);
        self.net.backward(&classifier_gradient[0 .. 1]);

        self.worker.compute_update(&self.config, &mut self.net, self.iter);
        self.net.update_weights(self.worker.backend());
        self.iter += 1;

        network_out
    }

    /// Returns the network trained by the solver.
    ///
    /// This is the recommended method to get a usable trained network.
    pub fn network(&self) -> &Layer<B> {
        &self.net
    }

    /// Returns the network trained by the solver.
    ///
    /// This is the recommended method to get a trained network,
    /// if you want to alter the network. Keep in mind that altering the network
    /// might render the solver unusable and continuing training the network with it will yield
    /// unexpected results.
    pub fn mut_network(&mut self) -> &mut Layer<B> {
        &mut self.net
    }
}

/// Implementation of a specific Solver.
///
/// See [Solvers][1]
/// [1]: ../solvers/index.html
pub trait ISolver<SolverB, B: IBackend + LayerOps<f32>> {
    /// Initialize the solver, setting up any network related data.
    fn init(&mut self, net: &Layer<B>) {}

    /// Update the weights of the net with part of the gradient.
    ///
    /// The [second phase of backpropagation learning][1].
    /// Calculates the gradient update that should be applied to the network,
    /// and then applies that gradient to the network, changing its weights.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Backpropagation#Phase_2:_Weight_update
    ///
    /// Used by [step][2] to optimize the network.
    ///
    /// [2]: ./struct.Solver.html#method.step
    fn compute_update(&mut self, param: &SolverConfig, network: &mut Layer<B>, iter: usize);

    /// Returns the backend used by the solver.
    fn backend(&self) -> &SolverB;
}

impl<SolverB, B: IBackend + LayerOps<f32>> ::std::fmt::Debug for ISolver<SolverB, B> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "({})", "ILayer")
    }
}

#[derive(Debug, Clone)]
/// Configuration for a Solver
pub struct SolverConfig {
    /// Name of the solver.
    pub name: String,
    /// The [LayerConfig][1] that is used to initialize the network.
    /// [1]: ../layer/struct.LayerConfig.html
    pub network: LayerConfig,
    /// The [LayerConfig][1] that is used to initialize the objective.
    /// [1]: ../layer/struct.LayerConfig.html
    pub objective: LayerConfig,
    /// The [Solver implementation][1] to be used.
    /// [1]: ../solvers/index.html
    pub solver: SolverKind,
    /// Accumulate gradients over `minibatch_size` instances.
    ///
    /// Default: 1
    pub minibatch_size: usize,
    /// The learning rate policy to be used.
    ///
    /// Default: Fixed
    pub lr_policy: LRPolicy,
    /// The base learning rate.
    ///
    /// Default: 0.01
    pub base_lr: f32,
    /// gamma as used in the calculation of most learning rate policies.
    ///
    /// Default: 0.1
    pub gamma: f32,
    /// The stepsize used in Step and Sigmoid learning policies.
    ///
    /// Default: 10
    pub stepsize: usize,
    /// The threshold for clipping gradients.
    ///
    /// Gradient values will be scaled to their [L2 norm][1] of length `clip_gradients`
    /// if their L2 norm is larger than `clip_gradients`.
    /// If set to `None` gradients will not be clipped.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm
    ///
    /// Default: None
    pub clip_gradients: Option<f32>,
    /// The global [weight decay][1] multiplier for [regularization][2].
    /// [1]: http://www.alglib.net/dataanalysis/improvinggeneralization.php#header3
    /// [2]: https://cs231n.github.io/neural-networks-2/#reg
    ///
    /// Regularization can prevent [overfitting][3].
    ///
    /// If set to `None` no regularization will be performed.
    ///
    /// [3]: https://cs231n.github.io/neural-networks-2/#reg
    pub weight_decay: Option<f32>,
    /// The method of [regularization][1] to use.
    /// [1]: https://cs231n.github.io/neural-networks-2/#reg
    ///
    /// There are different methods for regularization.
    /// The two most common ones are [L1 regularization][1] and [L2 regularization][1].
    ///
    /// See [RegularizationMethod][2] for all implemented methods.
    ///
    /// [2]: ./enum.RegularizationMethod.html
    ///
    /// Currently only L2 regularization is implemented.
    /// See [Issue #23](https://github.com/autumnai/leaf/issues/23).
    pub regularization_method: Option<RegularizationMethod>,
    /// The [momentum][1] multiplier for [SGD solvers][2].
    /// [1]: https://en.wikipedia.org/wiki/Stochastic_gradient_descent#Momentum
    /// [2]: ../solvers/sgd/index.html
    ///
    /// For more information see [SGD with momentum][3]
    /// [3]: ../solvers/sgd/momentum/index.html
    ///
    /// The value should always be between 0 and 1 and dictates how much of the previous
    /// gradient update will be added to the current one.
    ///
    /// Default: 0
    pub momentum: f32,
}

impl Default for SolverConfig {
    fn default() -> SolverConfig {
        SolverConfig {
            name: "".to_owned(),
            network: LayerConfig::new("default", SequentialConfig::default()),
            objective: LayerConfig::new("default", SequentialConfig::default()),
            solver: SolverKind::SGD(SGDKind::Momentum),

            minibatch_size: 1,

            lr_policy: LRPolicy::Fixed,
            base_lr: 0.01f32,
            gamma: 0.1f32,
            stepsize: 10,

            clip_gradients: None,

            weight_decay: None,
            regularization_method: None,

            momentum: 0f32,
        }
    }
}

impl SolverConfig {
    /// Return the learning rate for a supplied iteration.
    ///
    /// The way the learning rate is calculated depends on the configured [LRPolicy][1].
    ///
    /// [1]: ./enum.LRPolicy.html
    ///
    /// Used by the [Solver][2] to calculate the learning rate for the current iteration.
    /// The calculated learning rate has a different effect on training dependent on what
    /// [type of Solver][3] you are using.
    ///
    /// [2]: ./struct.Solver.html
    /// [3]: ../solvers/index.html
    pub fn get_learning_rate(&self, iter: usize) -> f32 {
        match self.lr_policy() {
            LRPolicy::Fixed => {
                self.base_lr()
            }
            LRPolicy::Step => {
                let current_step = self.step(iter);
                self.base_lr() * self.gamma().powf(current_step as f32)
            }
            // LRPolicy::Multistep => {
            //     // TODO: the current step can be calculated on-demand
            //     //   if (this->current_step_ < this->param_.stepvalue_size() &&
            //     //         this->iter_ >= this->param_.stepvalue(this->current_step_)) {
            //     //     this->current_step_++;
            //     //     LOG(INFO) << "MultiStep Status: Iteration " <<
            //     //     this->iter_ << ", step = " << this->current_step_;
            //     //   }
            //     //   rate = this->param_.base_lr() *
            //     //       pow(this->param_.gamma(), this->current_step_);
            //     unimplemented!();
            // }
            LRPolicy::Exp => {
                self.base_lr() * self.gamma().powf(iter as f32)
            }
            // LRPolicy::Inv => {
            //     //   rate = this->param_.base_lr() *
            //     //       pow(Dtype(1) + this->param_.gamma() * this->iter_,
            //     //           - this->param_.power());
            //     unimplemented!();
            // }
            // LRPolicy::Poly => {
            //     //   rate = this->param_.base_lr() * pow(Dtype(1.) -
            //     //       (Dtype(this->iter_) / Dtype(this->param_.max_iter())),
            //     //       this->param_.power());
            //     unimplemented!();
            // }
            // LRPolicy::Sigmoid => {
            //     //   rate = this->param_.base_lr() * (Dtype(1.) /
            //     //       (Dtype(1.) + exp(-this->param_.gamma() * (Dtype(this->iter_) -
            //     //         Dtype(this->param_.stepsize())))));
            //     unimplemented!();
            // }
        }
    }

    /// Return current step at iteration `iter`.
    ///
    /// Small helper for learning rate calculation.
    fn step(&self, iter: usize) -> usize {
        iter / self.stepsize()
    }

    /// Return learning rate policy.
    fn lr_policy(&self) -> LRPolicy {
        self.lr_policy
    }

    /// Return the base learning rate.
    fn base_lr(&self) -> f32 {
        self.base_lr
    }

    /// Return the gamma for learning rate calculations.
    fn gamma(&self) -> f32 {
        self.gamma
    }

    /// Return the stepsize for learning rate calculations.
    fn stepsize(&self) -> usize {
        self.stepsize
    }
}

#[derive(Debug, Copy, Clone)]
/// All available types of solvers.
pub enum SolverKind {
    /// Stochastic Gradient Descent.
    /// See [SGDKind][1] for all available SGD solvers.
    /// [1]: ./enum.SGDKind.html
    SGD(SGDKind),
}

impl SolverKind {
    /// Create a Solver of the specified kind with the supplied SolverConfig.
    pub fn with_config<B: IBackend + SolverOps<f32> + 'static, NetB: IBackend + LayerOps<f32> + 'static>(&self, backend: Rc<B>, config: &SolverConfig) -> Box<ISolver<B, NetB>> {
        match *self {
            SolverKind::SGD(sgd) => {
                sgd.with_config(backend, config)
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// All available types of Stochastic Gradient Descent solvers.
pub enum SGDKind {
    /// Stochastic Gradient Descent with Momentum. See [implementation][1]
    /// [1] ../solvers/
    Momentum,
}

impl SGDKind {
    /// Create a Solver of the specified kind with the supplied SolverConfig.
    pub fn with_config<B: IBackend + SolverOps<f32> + 'static, NetB: IBackend + LayerOps<f32> + 'static>(&self, backend: Rc<B>, config: &SolverConfig) -> Box<ISolver<B, NetB>> {
        match *self {
            SGDKind::Momentum => {
                Box::new(Momentum::<B>::new(backend))
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
/// Learning Rate Policy for a [Solver][1]
/// [1]: ./struct.Solver.html
///
/// The variables mentioned below are defined in the [SolverConfig][2] apart from
/// iter, which is the current iteration of the solver, that is supplied as a parameter
/// for the learning rate calculation.
///
/// [2]: ./struct.SolverConfig.html
pub enum LRPolicy {
    /// always return base_lr
    Fixed,
    /// learning rate decays every `step` iterations.
    /// return base_lr * gamma ^ (floor(iter / step))
    Step,
    // /// similar to step but it allows non uniform steps defined by
    // /// stepvalue
    // Multistep,
    /// return base_lr * gamma ^ iter
    Exp,
    // /// return base_lr * (1 + gamma * iter) ^ (- power)
    // Inv,
    // /// the effective learning rate follows a polynomial decay, to be
    // /// zero by the max_iter.
    // /// return base_lr (1 - iter/max_iter) ^ (power)
    // Poly,
    // /// the effective learning rate follows a sigmod decay
    // /// return base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))
    // Sigmoid,
}

#[derive(Debug, Copy, Clone)]
/// [Regularization][1] method for a [Solver][2].
/// [1]: https://cs231n.github.io/neural-networks-2/#reg
/// [2]: ./struct.Solver.html
pub enum RegularizationMethod {
    /// L2 regularization
    L2,
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Structures provided by D3D11
//!
//! # References
//! [D3D11 Structures, MSDN]
//! (https://msdn.microsoft.com/en-us/library/windows/desktop/ff476155(v=vs.85).aspx)<commit_msg>Add all graphics structures<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Structures provided by D3D11
//!
//! # References
//! [D3D11 Structures, MSDN]
//! (https://msdn.microsoft.com/en-us/library/windows/desktop/ff476155(v=vs.85).aspx)

type D3D11_RECT = RECT;

#[repr(C)] pub struct D3D11_RENDER_TARGET_BLEND_DESC {
	BlendEnable: BOOL,
	SrcBlend: D3D11_BLEND,
	DestBlend: D3D11_BLEND,
	BlendOp: D3D11_BLEND_OP,
	SrcBlendAlpha: D3D11_BLEND,
	DestBlendAlpha: D3D11_BLEND,
	BlendOpAlpha: D3D11_BLEND_OP,
	RenderTargetWriteMask: UINT8,
}

#[repr(C)] pub struct D3D11_RENDER_TARGET_BLEND_DESC1 {
	BlendEnable: BOOL,
	LogicOpEnable: BOOL,
	SrcBlend: D3D11_BLEND,
	DestBlend: D3D11_BLEND,
	BlendOp: D3D11_BLEND_OP,
	SrcBlendAlpha: D3D11_BLEND,
	DestBlendAlpha: D3D11_BLEND,
	BlendOpAlpha: D3D11_BLEND_OP,
	LogicOp: D3D11_LOGIC_OP,
	RenderTargetWriteMask: UINT8,
}

#[repr(C)] pub struct D3D11_BOX {
	left: UINT,
	top: UINT,
	front: UINT,
	right: UINT,
	bottom: UINT,
	back: UINT,
}

#[repr(C)] pub struct D3D11_COUNTER_DESC {
	Counter: D3D11_COUNTER,
	MiscFlags: UINT,
}

#[repr(C)] pub struct D3D11_COUNTER_INFO {
	LastDeviceDependentCounter: D3D11_COUNTER,
	NumSimultaneousCounters: UINT,
	NumDetectableParallelUnits: UINT8,
}

#[repr(C)] pub struct D3D11_DEPTH_STENCIL_DESC {
	DepthEnable: BOOL,
	DepthWriteMask: D3D11_DEPTH_WRITE_MASK,
	DepthFunc: D3D11_COMPARISON_FUNC,
	StencilEnable: BOOL,
	StencilReadMask: UINT8,
	StencilWriteMask: UINT8,
	FrontFace: D3D11_DEPTH_STENCILOP_DESC,
	BackFace: D3D11_DEPTH_STENCILOP_DESC,
}

#[repr(C)] pub struct D3D11_DEPTH_STENCILOP_DESC {
	StencilFailOp: D3D11_STENCIL_OP,
	StencilDepthFailOp: D3D11_STENCIL_OP,
	StencilPassOp: D3D11_STENCIL_OP,
	StencilFunc: D3D11_COMPARISON_FUNC,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_ARCHITECTURE_INFO {
	TileBasedDeferredRenderer: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D9_OPTIONS {
	FullNonPow2TextureSupport: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT {
	SupportsDepthAsTextureWithLessEqualComparisonFilter: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT {
	SimpleInstancingSupported: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS {
	ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D11_OPTIONS {
	OutputMergerLogicOp: BOOL,
	UAVOnlyRenderingForcedSampleCount: BOOL,
	DiscardAPIsSeenByDriver: BOOL,
	FlagsForUpdateAndCopySeenByDriver: BOOL,
	ClearView: BOOL,
	CopyWithOverlap: BOOL,
	ConstantBufferPartialUpdate: BOOL,
	ConstantBufferOffsetting: BOOL,
	MapNoOverwriteOnDynamicConstantBuffer: BOOL,
	MapNoOverwriteOnDynamicBufferSRV: BOOL,
	MultisampleRTVWithForcedSampleCountOne: BOOL,
	SAD4ShaderInstructions: BOOL,
	ExtendedDoublesShaderInstructions: BOOL,
	ExtendedResourceSharing: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_D3D11_OPTIONS1 {
	TiledResourcesTier: D3D11_TILED_RESOURCES_TIER,
	MinMaxFiltering: BOOL,
	ClearViewAlsoSupportsDepthOnlyFormats: BOOL,
	MapOnDefaultBuffers: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_DOUBLES {
	DoublePrecisionFloatShaderOps: BOOL,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_FORMAT_SUPPORT {
	InFormat: DXGI_FORMAT,
	OutFormatSupport: UINT,
	}struct D3D11_FEATURE_DATA_FORMAT_SUPPORT2
	{
	InFormat: DXGI_FORMAT,
	OutFormatSupport2: UINT,
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_MARKER_SUPPORT {
	Profile: BOOL,
	}
	D3D11_SHADER_MIN_PRECISION_SUPPORT
	{
		D3D11_SHADER_MIN_PRECISION_10_BIT	=0x1: ,
		D3D11_SHADER_MIN_PRECISION_16_BIT	= 0x2
}

#[repr(C)] pub struct D3D11_FEATURE_DATA_THREADING {
	DriverConcurrentCreates: BOOL,
	DriverCommandLists: BOOL,
}

#[repr(C)] pub struct D3D11_INPUT_ELEMENT_DESC {
	SemanticName: LPCSTR,
	SemanticIndex: UINT,
	Format: DXGI_FORMAT,
	InputSlot: UINT,
	AlignedByteOffset: UINT,
	InputSlotClass: D3D11_INPUT_CLASSIFICATION,
	InstanceDataStepRate: UINT,
}

#[repr(C)] pub struct D3D11_QUERY_DATA_PIPELINE_STATISTICS {
	IAVertices: UINT64,
	IAPrimitives: UINT64,
	VSInvocations: UINT64,
	GSInvocations: UINT64,
	GSPrimitives: UINT64,
	CInvocations: UINT64,
	CPrimitives: UINT64,
	PSInvocations: UINT64,
	HSInvocations: UINT64,
	DSInvocations: UINT64,
	CSInvocations: UINT64,
}

#[repr(C)] pub struct D3D11_QUERY_DATA_SO_STATISTICS {
	NumPrimitivesWritten: UINT64,
	PrimitivesStorageNeeded: UINT64,
}

#[repr(C)] pub struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT {
	Frequency: UINT64,
	Disjoint: BOOL,
}

#[repr(C)] pub struct D3D11_QUERY_DESC {
	Query: D3D11_QUERY,
	MiscFlags: UINT,
}

#[repr(C)] pub struct D3D11_RASTERIZER_DESC {
	FillMode: D3D11_FILL_MODE,
	CullMode: D3D11_CULL_MODE,
	FrontCounterClockwise: BOOL,
	DepthBias: INT,
	DepthBiasClamp: FLOAT,
	SlopeScaledDepthBias: FLOAT,
	DepthClipEnable: BOOL,
	ScissorEnable: BOOL,
	MultisampleEnable: BOOL,
	AntialiasedLineEnable: BOOL,
}

#[repr(C)] pub struct D3D11_RASTERIZER_DESC1 {
	FillMode: D3D11_FILL_MODE,
	CullMode: D3D11_CULL_MODE,
	FrontCounterClockwise: BOOL,
	DepthBias: INT,
	DepthBiasClamp: FLOAT,
	SlopeScaledDepthBias: FLOAT,
	DepthClipEnable: BOOL,
	ScissorEnable: BOOL,
	MultisampleEnable: BOOL,
	AntialiasedLineEnable: BOOL,
	ForcedSampleCount: UINT,
}

#[repr(C)] pub struct D3D11_RENDER_TARGET_BLEND_DESC {
	BlendEnable: BOOL,
	SrcBlend: D3D11_BLEND,
	DestBlend: D3D11_BLEND,
	BlendOp: D3D11_BLEND_OP,
	SrcBlendAlpha: D3D11_BLEND,
	DestBlendAlpha: D3D11_BLEND,
	BlendOpAlpha: D3D11_BLEND_OP,
	RenderTargetWriteMask: UINT8,
}

#[repr(C)] pub struct D3D11_RENDER_TARGET_BLEND_DESC1 {
	BlendEnable: BOOL,
	LogicOpEnable: BOOL,
	SrcBlend: D3D11_BLEND,
	DestBlend: D3D11_BLEND,
	BlendOp: D3D11_BLEND_OP,
	SrcBlendAlpha: D3D11_BLEND,
	DestBlendAlpha: D3D11_BLEND,
	BlendOpAlpha: D3D11_BLEND_OP,
	LogicOp: D3D11_LOGIC_OP,
	RenderTargetWriteMask: UINT8,
}

#[repr(C)] pub struct D3D11_SAMPLER_DESC {
	Filter: D3D11_FILTER,
	AddressU: D3D11_TEXTURE_ADDRESS_MODE,
	AddressV: D3D11_TEXTURE_ADDRESS_MODE,
	AddressW: D3D11_TEXTURE_ADDRESS_MODE,
	MipLODBias: FLOAT,
	MaxAnisotropy: UINT,
	ComparisonFunc: D3D11_COMPARISON_FUNC,
	FLOAT BorderColor[ 4 ],
	MinLOD: FLOAT,
	MaxLOD: FLOAT,
}

#[repr(C)] pub struct D3D11_SO_DECLARATION_ENTRY {
	Stream: UINT,
	SemanticName: LPCSTR,
	SemanticIndex: UINT,
	StartComponent: BYTE,
	ComponentCount: BYTE,
	OutputSlot: BYTE,
}

#[repr(C)] pub struct D3D11_VIEWPORT {
	TopLeftX: FLOAT,
	TopLeftY: FLOAT,
	Width: FLOAT,
	Height: FLOAT,
	MinDepth: FLOAT,
	MaxDepth: FLOAT,
}<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

#[cfg(feature = "local-run")]
pub mod bin_resolver;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod debian_base;

#[cfg(feature = "local-run")]
#[allow(dead_code)]
pub mod default_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod linux_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod redhat_base;

#[cfg(all(target_family = "unix", feature = "local-run"))]
#[allow(dead_code)]
pub mod unix_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod debian;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod centos;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod fedora;

#[cfg(all(target_os = "freebsd", feature = "local-run"))]
pub mod freebsd;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod linux;

#[cfg(all(target_os = "macos", feature = "local-run"))]
pub mod macos;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod redhat;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod ubuntu;

#[cfg(feature = "remote-run")]
pub mod remote;

pub struct Target;
<commit_msg>Fix bug identifying unix target that caused target::unix_base to be loaded erroneously<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

#[cfg(feature = "local-run")]
pub mod bin_resolver;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod debian_base;

#[cfg(feature = "local-run")]
#[allow(dead_code)]
pub mod default_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod linux_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod redhat_base;

#[cfg(all(any(target_os = "freebsd", target_os = "macos"), feature = "local-run"))]
#[allow(dead_code)]
pub mod unix_base;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod debian;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod centos;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod fedora;

#[cfg(all(target_os = "freebsd", feature = "local-run"))]
pub mod freebsd;

#[cfg(all(target_os = "linux", feature = "local-run"))]
#[allow(dead_code)]
pub mod linux;

#[cfg(all(target_os = "macos", feature = "local-run"))]
pub mod macos;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod redhat;

#[cfg(all(target_os = "linux", feature = "local-run"))]
pub mod ubuntu;

#[cfg(feature = "remote-run")]
pub mod remote;

pub struct Target;
<|endoftext|>


<commit_before>use crate::util;
use proc_macro::TokenStream;
use quote::quote;

/// Generate code for the juniper::object macro.
pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) -> TokenStream {
    let impl_attrs = match syn::parse::<util::ObjectAttributes>(args) {
        Ok(attrs) => attrs,
        Err(e) => {
            panic!("Invalid attributes:\n{}", e);
        }
    };

    let item = match syn::parse::<syn::Item>(body) {
        Ok(item) => item,
        Err(err) => {
            panic!("Parsing error:\n{}", err);
        }
    };
    let mut _impl = match item {
        syn::Item::Impl(_impl) => _impl,
        _ => {
            panic!("#[juniper::object] can only be applied to impl blocks");
        }
    };

    match _impl.trait_ {
        Some((_, ref path, _)) => {
            let name = path
                .segments
                .iter()
                .map(|segment| segment.ident.to_string())
                .collect::<Vec<_>>()
                .join(".");
            if !(name == "GraphQLObject" || name == "juniper.GraphQLObject") {
                panic!("The impl block must implement the 'GraphQLObject' trait");
            }
        }
        None => {
            // panic!("The impl block must implement the 'GraphQLObject' trait");
        }
    }

    let name = match impl_attrs.name.as_ref() {
        Some(type_name) => type_name.clone(),
        None => match &*_impl.self_ty {
            syn::Type::Path(ref type_path) => type_path
                .path
                .segments
                .iter()
                .last()
                .unwrap()
                .ident
                .to_string(),
            syn::Type::Reference(ref reference) => {
                let path = match &*reference.elem {
                    syn::Type::Path(ref type_path) => &type_path.path,
                    syn::Type::TraitObject(ref trait_obj) => {
                        match trait_obj.bounds.iter().nth(0).unwrap() {
                            syn::TypeParamBound::Trait(ref trait_bound) => &trait_bound.path,
                            _ => {
                                panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
                            }
                        }
                    }
                    _ => {
                        panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
                    }
                };
                path.segments.iter().last().unwrap().ident.to_string()
            }
            _ => {
                panic!("Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")");
            }
        },
    };

    let target_type = *_impl.self_ty.clone();

    let description = impl_attrs
        .description
        .or(util::get_doc_comment(&_impl.attrs));

    let mut definition = util::GraphQLTypeDefiniton {
        name,
        _type: target_type.clone(),
        context: impl_attrs.context,
        scalar: impl_attrs.scalar,
        description,
        fields: Vec::new(),
        generics: _impl.generics.clone(),
        interfaces: if impl_attrs.interfaces.len() > 0 {
            Some(impl_attrs.interfaces)
        } else {
            None
        },
        include_type_generics: false,
        generic_scalar: false,
    };

    for item in _impl.items {
        match item {
            syn::ImplItem::Method(method) => {
                let _type = match &method.sig.decl.output {
                    syn::ReturnType::Type(_, ref t) => (**t).clone(),
                    syn::ReturnType::Default => {
                        panic!(
                            "Invalid field method {}: must return a value",
                            method.sig.ident
                        );
                    }
                };

                let attrs = match util::FieldAttributes::from_attrs(
                    method.attrs,
                    util::FieldAttributeParseMode::Impl,
                ) {
                    Ok(attrs) => attrs,
                    Err(err) => panic!(
                        "Invalid #[graphql(...)] attribute on field {}:\n{}",
                        method.sig.ident, err
                    ),
                };

                let mut args = Vec::new();
                let mut resolve_parts = Vec::new();

                for arg in method.sig.decl.inputs {
                    match arg {
                        _self @ syn::FnArg::SelfRef(_) => {
                            // Can be ignored.
                            // "self" will already be in scope.
                            // resolve_args.push(quote!(self));
                        }
                        syn::FnArg::SelfValue(_) => {
                            panic!(
                                "Invalid method receiver {}(self, ...): did you mean '&self'?",
                                method.sig.ident
                            );
                        }
                        syn::FnArg::Captured(ref captured) => {
                            let arg_ident = match &captured.pat {
                                syn::Pat::Ident(ref pat_ident) => &pat_ident.ident,
                                _ => {
                                    panic!("Invalid token for function argument");
                                }
                            };
                            let arg_name = arg_ident.to_string();

                            let context_type = definition.context.as_ref();

                            // Check for executor arguments.
                            if util::type_is_identifier_ref(&captured.ty, "Executor") {
                                resolve_parts.push(quote!(let #arg_ident = executor;));
                            }
                            // Make sure executor is specified as a reference.
                            else if util::type_is_identifier(&captured.ty, "Executor") {
                                panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?");
                            }
                            // Check for executor arg.
                            else if context_type
                                .clone()
                                .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                                .unwrap_or(false)
                            {
                                resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                            }
                            // Make sure the user does not specify the Context
                            //  without a reference. (&Context)
                            else if context_type
                                .clone()
                                .map(|ctx| ctx == &captured.ty)
                                .unwrap_or(false)
                            {
                                panic!(
                                    "Invalid context argument: to access the context, you need to specify the type as a reference.\nDid you mean &{}?",
                                    quote!(captured.ty),
                                );
                            } else {
                                let ty = &captured.ty;
                                // TODO: respect graphql attribute overwrite.
                                let final_name = util::to_camel_case(&arg_name);
                                let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name);
                                resolve_parts.push(quote!(
                                    let #arg_ident = args
                                        .get::<#ty>(#final_name)
                                        .expect(#expect_text);
                                ));
                                args.push(util::GraphQLTypeDefinitionFieldArg {
                                    description: attrs.argument(&arg_name).and_then(|arg| {
                                        arg.description.as_ref().map(|d| d.value())
                                    }),
                                    default: attrs
                                        .argument(&arg_name)
                                        .and_then(|arg| arg.default.clone()),
                                    _type: ty.clone(),
                                    name: final_name,
                                })
                            }
                        }
                        _ => panic!("Invalid argument type in method {}", method.sig.ident),
                    }
                }

                let body = &method.block;
                let return_ty = &method.sig.decl.output;
                let resolver_code = quote!(
                    (|| #return_ty {
                        #( #resolve_parts )*
                        #body
                    })()
                );

                let ident = &method.sig.ident;
                let name = attrs
                    .name
                    .unwrap_or_else(|| util::to_camel_case(&ident.to_string()));

                definition.fields.push(util::GraphQLTypeDefinitionField {
                    name,
                    _type,
                    args,
                    description: attrs.description,
                    deprecation: attrs.deprecation,
                    resolver_code,
                });
            }
            _ => {
                panic!("Invalid item for GraphQL Object: only type declarations and methods are allowed");
            }
        }
    }
    let juniper_crate_name = if is_internal { "crate" } else { "juniper" };
    definition.into_tokens(juniper_crate_name).into()
}
<commit_msg>Cleanup after #385 (#386)<commit_after>use crate::util;
use proc_macro::TokenStream;
use quote::quote;

/// Generate code for the juniper::object macro.
pub fn build_object(args: TokenStream, body: TokenStream, is_internal: bool) -> TokenStream {
    let impl_attrs = match syn::parse::<util::ObjectAttributes>(args) {
        Ok(attrs) => attrs,
        Err(e) => {
            panic!("Invalid attributes:\n{}", e);
        }
    };

    let item = match syn::parse::<syn::Item>(body) {
        Ok(item) => item,
        Err(err) => {
            panic!("Parsing error:\n{}", err);
        }
    };
    let mut _impl = match item {
        syn::Item::Impl(_impl) => _impl,
        _ => {
            panic!("#[juniper::object] can only be applied to impl blocks");
        }
    };

    match _impl.trait_ {
        Some((_, ref path, _)) => {
            let name = path
                .segments
                .iter()
                .map(|segment| segment.ident.to_string())
                .collect::<Vec<_>>()
                .join(".");
            if !(name == "GraphQLObject" || name == "juniper.GraphQLObject") {
                panic!("The impl block must implement the 'GraphQLObject' trait");
            }
        }
        None => {
            // panic!("The impl block must implement the 'GraphQLObject' trait");
        }
    }

    let name = match impl_attrs.name.as_ref() {
        Some(type_name) => type_name.clone(),
        None => {
            let error_msg = "Could not determine a name for the object type: specify one with #[juniper::object(name = \"SomeName\")";

            let path = match &*_impl.self_ty {
                syn::Type::Path(ref type_path) => &type_path.path,
                syn::Type::Reference(ref reference) => match &*reference.elem {
                    syn::Type::Path(ref type_path) => &type_path.path,
                    syn::Type::TraitObject(ref trait_obj) => {
                        match trait_obj.bounds.iter().nth(0).unwrap() {
                            syn::TypeParamBound::Trait(ref trait_bound) => &trait_bound.path,
                            _ => panic!(error_msg),
                        }
                    }
                    _ => panic!(error_msg),
                },
                _ => panic!(error_msg),
            };

            path.segments.iter().last().unwrap().ident.to_string()
        }
    };

    let target_type = *_impl.self_ty.clone();

    let description = impl_attrs
        .description
        .or(util::get_doc_comment(&_impl.attrs));

    let mut definition = util::GraphQLTypeDefiniton {
        name,
        _type: target_type.clone(),
        context: impl_attrs.context,
        scalar: impl_attrs.scalar,
        description,
        fields: Vec::new(),
        generics: _impl.generics.clone(),
        interfaces: if impl_attrs.interfaces.len() > 0 {
            Some(impl_attrs.interfaces)
        } else {
            None
        },
        include_type_generics: false,
        generic_scalar: false,
    };

    for item in _impl.items {
        match item {
            syn::ImplItem::Method(method) => {
                let _type = match &method.sig.decl.output {
                    syn::ReturnType::Type(_, ref t) => (**t).clone(),
                    syn::ReturnType::Default => {
                        panic!(
                            "Invalid field method {}: must return a value",
                            method.sig.ident
                        );
                    }
                };

                let attrs = match util::FieldAttributes::from_attrs(
                    method.attrs,
                    util::FieldAttributeParseMode::Impl,
                ) {
                    Ok(attrs) => attrs,
                    Err(err) => panic!(
                        "Invalid #[graphql(...)] attribute on field {}:\n{}",
                        method.sig.ident, err
                    ),
                };

                let mut args = Vec::new();
                let mut resolve_parts = Vec::new();

                for arg in method.sig.decl.inputs {
                    match arg {
                        _self @ syn::FnArg::SelfRef(_) => {
                            // Can be ignored.
                            // "self" will already be in scope.
                            // resolve_args.push(quote!(self));
                        }
                        syn::FnArg::SelfValue(_) => {
                            panic!(
                                "Invalid method receiver {}(self, ...): did you mean '&self'?",
                                method.sig.ident
                            );
                        }
                        syn::FnArg::Captured(ref captured) => {
                            let arg_ident = match &captured.pat {
                                syn::Pat::Ident(ref pat_ident) => &pat_ident.ident,
                                _ => {
                                    panic!("Invalid token for function argument");
                                }
                            };
                            let arg_name = arg_ident.to_string();

                            let context_type = definition.context.as_ref();

                            // Check for executor arguments.
                            if util::type_is_identifier_ref(&captured.ty, "Executor") {
                                resolve_parts.push(quote!(let #arg_ident = executor;));
                            }
                            // Make sure executor is specified as a reference.
                            else if util::type_is_identifier(&captured.ty, "Executor") {
                                panic!("Invalid executor argument: to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?");
                            }
                            // Check for executor arg.
                            else if context_type
                                .clone()
                                .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                                .unwrap_or(false)
                            {
                                resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                            }
                            // Make sure the user does not specify the Context
                            //  without a reference. (&Context)
                            else if context_type
                                .clone()
                                .map(|ctx| ctx == &captured.ty)
                                .unwrap_or(false)
                            {
                                panic!(
                                    "Invalid context argument: to access the context, you need to specify the type as a reference.\nDid you mean &{}?",
                                    quote!(captured.ty),
                                );
                            } else {
                                let ty = &captured.ty;
                                // TODO: respect graphql attribute overwrite.
                                let final_name = util::to_camel_case(&arg_name);
                                let expect_text = format!("Internal error: missing argument {} - validation must have failed", &final_name);
                                resolve_parts.push(quote!(
                                    let #arg_ident = args
                                        .get::<#ty>(#final_name)
                                        .expect(#expect_text);
                                ));
                                args.push(util::GraphQLTypeDefinitionFieldArg {
                                    description: attrs.argument(&arg_name).and_then(|arg| {
                                        arg.description.as_ref().map(|d| d.value())
                                    }),
                                    default: attrs
                                        .argument(&arg_name)
                                        .and_then(|arg| arg.default.clone()),
                                    _type: ty.clone(),
                                    name: final_name,
                                })
                            }
                        }
                        _ => panic!("Invalid argument type in method {}", method.sig.ident),
                    }
                }

                let body = &method.block;
                let return_ty = &method.sig.decl.output;
                let resolver_code = quote!(
                    (|| #return_ty {
                        #( #resolve_parts )*
                        #body
                    })()
                );

                let ident = &method.sig.ident;
                let name = attrs
                    .name
                    .unwrap_or_else(|| util::to_camel_case(&ident.to_string()));

                definition.fields.push(util::GraphQLTypeDefinitionField {
                    name,
                    _type,
                    args,
                    description: attrs.description,
                    deprecation: attrs.deprecation,
                    resolver_code,
                });
            }
            _ => {
                panic!("Invalid item for GraphQL Object: only type declarations and methods are allowed");
            }
        }
    }
    let juniper_crate_name = if is_internal { "crate" } else { "juniper" };
    definition.into_tokens(juniper_crate_name).into()
}
<|endoftext|>


<commit_before>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.len() == 0 {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or(buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter: iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! impl_tuple_collect {
    () => ();
    ($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => (
        impl<$A> TupleCollect for ($($X),*,) {
            type Item = $A;
            type Buffer = [Option<$A>; $N - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = $A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            #[allow(unused_assignments)]
            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = $A>
            {
                let mut iter = iter.into_iter();
                loop {
                    $(
                        let $Y = if let Some($Y) = iter.next() {
                            $Y
                        } else {
                            break;
                        };
                    )*
                    return Some(($($Y),*,))
                }

                return None;
            }

            fn num_items() -> usize {
                $N
            }

            fn left_shift_push(&mut self, item: $A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                let tmp = item;
                $(
                    let tmp = replace($Y_rev, tmp);
                )*
                drop(tmp);
            }
        }
    )
}

impl_tuple_collect!(1; A; A; a; a);
impl_tuple_collect!(2; A; A, A; a, b; b, a);
impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a);
impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a);
<commit_msg>Remove unused macro variant<commit_after>//! Some iterator that produces tuples

use std::iter::Fuse;
use std::iter::Take;
use std::iter::Cycle;
use std::marker::PhantomData;

// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
// tuple-related methods to be used by clients in generic contexts, while
// hiding the implementation details of `TupleCollect`.
// See https://github.com/rust-itertools/itertools/issues/387

/// Implemented for homogeneous tuples of size up to 4.
pub trait HomogeneousTuple
    : TupleCollect
{}

impl<T: TupleCollect> HomogeneousTuple for T {}

/// An iterator over a incomplete tuple.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
#[derive(Clone, Debug)]
pub struct TupleBuffer<T>
    where T: HomogeneousTuple
{
    cur: usize,
    buf: T::Buffer,
}

impl<T> TupleBuffer<T>
    where T: HomogeneousTuple
{
    fn new(buf: T::Buffer) -> Self {
        TupleBuffer {
            cur: 0,
            buf,
        }
    }
}

impl<T> Iterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        let s = self.buf.as_mut();
        if let Some(ref mut item) = s.get_mut(self.cur) {
            self.cur += 1;
            item.take()
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = &self.buf.as_ref()[self.cur..];
        let len = if buffer.len() == 0 {
            0
        } else {
            buffer.iter()
                  .position(|x| x.is_none())
                  .unwrap_or(buffer.len())
        };
        (len, Some(len))
    }
}

impl<T> ExactSizeIterator for TupleBuffer<T>
    where T: HomogeneousTuple
{
}

/// An iterator that groups the items in tuples of a specific size.
///
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: Fuse<I>,
    buf: T::Buffer,
}

/// Create a new tuples iterator.
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    Tuples {
        iter: iter.fuse(),
        buf: Default::default(),
    }
}

impl<I, T> Iterator for Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        T::collect_from_iter(&mut self.iter, &mut self.buf)
    }
}

impl<I, T> Tuples<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let mut iter = (0..5).tuples();
    /// assert_eq!(Some((0, 1, 2)), iter.next());
    /// assert_eq!(None, iter.next());
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
    /// ```
    pub fn into_buffer(self) -> TupleBuffer<T> {
        TupleBuffer::new(self.buf)
    }
}

/// An iterator over all contiguous windows that produces tuples of a specific size.
///
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple
{
    iter: I,
    last: Option<T>,
}

/// Create a new tuple windows iterator.
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple,
          T::Item: Clone
{
    use std::iter::once;

    let mut last = None;
    if T::num_items() != 1 {
        // put in a duplicate item in front of the tuple; this simplifies
        // .next() function.
        if let Some(item) = iter.next() {
            let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
            last = T::collect_from_iter_no_buf(iter);
        }
    }

    TupleWindows {
        last,
        iter,
    }
}

impl<I, T> Iterator for TupleWindows<I, T>
    where I: Iterator<Item = T::Item>,
          T: HomogeneousTuple + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        if T::num_items() == 1 {
            return T::collect_from_iter_no_buf(&mut self.iter)
        }
        if let Some(ref mut last) = self.last {
            if let Some(new) = self.iter.next() {
                last.left_shift_push(new);
                return Some(last.clone());
            }
        }
        None
    }
}

/// An iterator over all windows,wrapping back to the first elements when the
/// window would otherwise exceed the length of the iterator, producing tuples
/// of a specific size.
///
/// See [`.circular_tuple_windows()`](../trait.Itertools.html#method.circular_tuple_windows) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct CircularTupleWindows<I, T: Clone>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone
{
    iter: Take<TupleWindows<Cycle<I>, T>>,
    phantom_data: PhantomData<T>
}

pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    let len = iter.len();
    let iter = tuple_windows(iter.cycle()).take(len);

    CircularTupleWindows {
        iter: iter,
        phantom_data: PhantomData{}
    }
}

impl<I, T> Iterator for CircularTupleWindows<I, T>
    where I: Iterator<Item = T::Item> + Clone,
          T: TupleCollect + Clone,
          T::Item: Clone
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.iter.next()
    }
}

pub trait TupleCollect: Sized {
    type Item;
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;

    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
        where I: IntoIterator<Item = Self::Item>;

    fn num_items() -> usize;

    fn left_shift_push(&mut self, item: Self::Item);
}

macro_rules! impl_tuple_collect {
    ($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => (
        impl<$A> TupleCollect for ($($X),*,) {
            type Item = $A;
            type Buffer = [Option<$A>; $N - 1];

            #[allow(unused_assignments, unused_mut)]
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
                where I: IntoIterator<Item = $A>
            {
                let mut iter = iter.into_iter();
                $(
                    let mut $Y = None;
                )*

                loop {
                    $(
                        $Y = iter.next();
                        if $Y.is_none() {
                            break
                        }
                    )*
                    return Some(($($Y.unwrap()),*,))
                }

                let mut i = 0;
                let mut s = buf.as_mut();
                $(
                    if i < s.len() {
                        s[i] = $Y;
                        i += 1;
                    }
                )*
                return None;
            }

            #[allow(unused_assignments)]
            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
                where I: IntoIterator<Item = $A>
            {
                let mut iter = iter.into_iter();
                loop {
                    $(
                        let $Y = if let Some($Y) = iter.next() {
                            $Y
                        } else {
                            break;
                        };
                    )*
                    return Some(($($Y),*,))
                }

                return None;
            }

            fn num_items() -> usize {
                $N
            }

            fn left_shift_push(&mut self, item: $A) {
                use std::mem::replace;

                let &mut ($(ref mut $Y),*,) = self;
                let tmp = item;
                $(
                    let tmp = replace($Y_rev, tmp);
                )*
                drop(tmp);
            }
        }
    )
}

impl_tuple_collect!(1; A; A; a; a);
impl_tuple_collect!(2; A; A, A; a, b; b, a);
impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a);
impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a);
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;
extern crate toml;
extern crate toml_query;

extern crate libimagbookmark;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

use std::process::exit;

use toml::Value;
use toml_query::read::TomlValueReadExt;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagutil::info_result::*;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("add").unwrap();
    let coll = get_collection_name(rt, "add", "collection");

    BookmarkCollection::get(rt.store(), &coll)
        .and_then(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap
                let _ = collection.add_link(BookmarkLink::from(url))?;
            }
            Ok(())
        })
        .map_err_trace()
        .map_info_str("Ready")
        .ok();
}

fn collection(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("collection").unwrap();

    if scmd.is_present("add") { // adding a new collection
        let name = scmd.value_of("add").unwrap();
        if let Ok(_) = BookmarkCollection::new(rt.store(), &name) {
            info!("Created: {}", name);
        } else {
            warn!("Creating collection {} failed", name);
            exit(1);
        }
    }

    if scmd.is_present("remove") { // remove a collection
        let name = scmd.value_of("remove").unwrap();
        if let Ok(_) = BookmarkCollection::delete(rt.store(), &name) {
            info!("Deleted: {}", name);
        } else {
            warn!("Deleting collection {} failed", name);
            exit(1);
        }
    }
}

fn list(rt: &Runtime) {
    let coll = get_collection_name(rt, "list", "collection");

    BookmarkCollection::get(rt.store(), &coll)
        .map(|collection| {
            match collection.links() {
                Ok(links) => {
                    debug!("Listing...");
                    for (i, link) in links.enumerate() {
                        match link {
                            Ok(link) => println!("{: >3}: {}", i, link),
                            Err(e)   => trace_error(&e)
                        }
                    };
                    debug!("... ready with listing");
                },
                Err(e) => trace_error_exit(&e, 1),
            }
        })
        .ok();
    info!("Ready");
}

fn remove(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("remove").unwrap();
    let coll = get_collection_name(rt, "list", "collection");

    BookmarkCollection::get(rt.store(), &coll)
        .map(|mut collection| {
            for url in scmd.values_of("urls").unwrap() { // enforced by clap
                collection.remove_link(BookmarkLink::from(url)).map_err(|e| trace_error(&e)).ok();
            }
        })
        .ok();
    info!("Ready");
}

fn get_collection_name(rt: &Runtime,
                       subcommand_name: &str,
                       collection_argument_name: &str)
    -> String
{
    rt.cli()
        .subcommand_matches(subcommand_name)
        .and_then(|scmd| scmd.value_of(collection_argument_name).map(String::from))
        .unwrap_or_else(|| {
            rt.config()
                .map(|cfg| match cfg.read("bookmark.default_collection") {
                    Err(e) => trace_error_exit(&e, 1),
                    Ok(Some(&Value::String(ref name))) => name.clone(),
                    Ok(None) => {
                        error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify.");
                        exit(1)
                    },

                    Ok(Some(_)) => {
                        error!("Type error in configuration: 'bookmark.default_collection' should be string");
                        exit(1)
                    }

                })
                .unwrap_or_else(|| {
                    error!("Failed to read configuration");
                    exit(1)
                })
        })
}

<commit_msg>Adapt for new API<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;
extern crate toml;
extern crate toml_query;

extern crate libimagbookmark;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

use std::process::exit;

use toml::Value;
use toml_query::read::TomlValueReadExt;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagbookmark::collection::BookmarkCollection;
use libimagbookmark::collection::BookmarkCollectionStore;
use libimagbookmark::error::BookmarkError as BE;
use libimagbookmark::link::Link as BookmarkLink;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-bookmark",
                                    &version!()[..],
                                    "Bookmark collection tool",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            debug!("Call {}", name);
            match name {
                "add"        => add(&rt),
                "collection" => collection(&rt),
                "list"       => list(&rt),
                "remove"     => remove(&rt),
                _            => {
                    debug!("Unknown command"); // More error handling
                },
            }
        });
}

fn add(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("add").unwrap();
    let coll = get_collection_name(rt, "add", "collection");

    let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
        .map_err_trace_exit_unwrap(1)
        .ok_or(BE::from(format!("No BookmarkcollectionStore '{}' found", coll)))
        .map_err_trace_exit_unwrap(1);

    for url in scmd.values_of("urls").unwrap() { // unwrap saved by clap
        let _ = collection
            .add_link(rt.store(), BookmarkLink::from(url))
            .map_err_trace_exit_unwrap(1);
    }

    info!("Ready");
}

fn collection(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("collection").unwrap();

    if scmd.is_present("add") { // adding a new collection
        let name = scmd.value_of("add").unwrap();
        if let Ok(_) = BookmarkCollectionStore::new(rt.store(), &name) {
            info!("Created: {}", name);
        } else {
            warn!("Creating collection {} failed", name);
            exit(1);
        }
    }

    if scmd.is_present("remove") { // remove a collection
        let name = scmd.value_of("remove").unwrap();
        if let Ok(_) = BookmarkCollectionStore::delete(rt.store(), &name) {
            info!("Deleted: {}", name);
        } else {
            warn!("Deleting collection {} failed", name);
            exit(1);
        }
    }
}

fn list(rt: &Runtime) {
    let coll = get_collection_name(rt, "list", "collection");

    let collection = BookmarkCollectionStore::get(rt.store(), &coll)
        .map_err_trace_exit_unwrap(1)
        .ok_or(BE::from(format!("No BookmarkcollectionStore '{}' found", coll)))
        .map_err_trace_exit_unwrap(1);

    match collection.links(rt.store()) {
        Ok(links) => {
            debug!("Listing...");
            for (i, link) in links.enumerate() {
                match link {
                    Ok(link) => println!("{: >3}: {}", i, link),
                    Err(e)   => trace_error(&e)
                }
            };
            debug!("... ready with listing");
        },
        Err(e) => trace_error_exit(&e, 1),
    }

    info!("Ready");
}

fn remove(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("remove").unwrap();
    let coll = get_collection_name(rt, "list", "collection");

    let mut collection = BookmarkCollectionStore::get(rt.store(), &coll)
        .map_err_trace_exit_unwrap(1)
        .ok_or(BE::from(format!("No BookmarkcollectionStore '{}' found", coll)))
        .map_err_trace_exit_unwrap(1);

    for url in scmd.values_of("urls").unwrap() { // enforced by clap
        collection
            .remove_link(rt.store(), BookmarkLink::from(url))
            .map_err_trace_exit_unwrap(1);
    }

    info!("Ready");
}

fn get_collection_name(rt: &Runtime,
                       subcommand_name: &str,
                       collection_argument_name: &str)
    -> String
{
    rt.cli()
        .subcommand_matches(subcommand_name)
        .and_then(|scmd| scmd.value_of(collection_argument_name).map(String::from))
        .unwrap_or_else(|| {
            rt.config()
                .map(|cfg| match cfg.read("bookmark.default_collection") {
                    Err(e) => trace_error_exit(&e, 1),
                    Ok(Some(&Value::String(ref name))) => name.clone(),
                    Ok(None) => {
                        error!("Missing config: 'bookmark.default_collection'. Set or use commandline to specify.");
                        exit(1)
                    },

                    Ok(Some(_)) => {
                        error!("Type error in configuration: 'bookmark.default_collection' should be string");
                        exit(1)
                    }

                })
                .unwrap_or_else(|| {
                    error!("Failed to read configuration");
                    exit(1)
                })
        })
}

<|endoftext|>