<commit_before>pub struct Player {
    pub health: u32,
    pub mana: Option<u32>,
    pub level: u32,
}

impl Player {
    pub fn revive(&self) -> Option<Player> {
        if self.health != 0_u32 {
            return None;
        } else if self.level >= 10 {
            return Some(Player {
                health: 100,
                mana: Some(100),
                level: self.level,
            });
        } else {
            return Some(Player {
                health: 100,
                mana: Some(0),
                level: self.level,
            });
        }
    }

    pub fn cast_spell(&mut self, mana_cost: u32) -> u32 {
        unimplemented!("Cast a spell of cost {}", mana_cost)
    }
}
<commit_msg>Refactor revive<commit_after>pub struct Player {
    pub health: u32,
    pub mana: Option<u32>,
    pub level: u32,
}

impl Player {
    pub fn revive(&self) -> Option<Player> {
        if self.health != 0_u32 {
            return None;
        }
        let mana = if self.level >= 10 { 100 } else { 0 };
        return Some(Player {
            health: 100,
            mana: Some(mana),
            level: self.level,
        });
    }

    pub fn cast_spell(&mut self, mana_cost: u32) -> u32 {
        unimplemented!("Cast a spell of cost {}", mana_cost)
    }
}
<|endoftext|>


<commit_before>use linalg::vector::Vector;
use linalg::matrix::Matrix;

use learning::SupModel;

pub struct GenLinearModel<C: Criterion> {
    parameters: Option<Vector<f64>>,
    criterion: C,
}

impl<C: Criterion> GenLinearModel<C> {

    /// Constructs a new Generalized Linear Model.
    ///
    /// Takes a Criterion which fully specifies the family
    /// and the link function used by the GLM.
    ///
    /// ```
    /// use rusty_machine::learning::glm::GenLinearModel;
    /// //use rusty_machine::learning::glm::Criterion;
    /// use rusty_machine::learning::glm::Bernoulli;
    ///
    /// let glm = GenLinearModel::new(Bernoulli);
    ///
    /// ```
	pub fn new(criterion: C) -> GenLinearModel<C> {
		GenLinearModel {
			parameters: None,
			criterion: criterion,
		}
	}
}

impl<C: Criterion> SupModel<Matrix<f64>, Vector<f64>> for GenLinearModel<C> {
    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let Some(ref v) = self.parameters {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            self.criterion.apply_link_inv(full_inputs * v)
        } else {
            panic!("The model has not been trained.");
        }
    }

    /// Train the model using inputs and targets.
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let n = inputs.rows();

        assert!(n == targets.size(),
                "Training data do not have the same dimensions.");

        // Construct initial estimate for mu
        let mut mu = Vector::new(self.criterion.initialize_mu(targets.data()));
        let mut z = mu.clone();
        let mut beta : Vector<f64> = Vector::new(vec![]);

        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);
        let x_t = full_inputs.transpose();

        // Iterate to convergence
        for _ in 0..8 {
            let w_diag = self.criterion.compute_working_weight(&mu.data());
            let y_bar_data = self.criterion.compute_y_bar(targets.data(), &mu.data());

            let w = Matrix::from_diag(&w_diag);
            let y_bar = Vector::new(y_bar_data);

            let x_t_w = &x_t * w;

            beta = (&x_t_w * &full_inputs).inverse() * x_t_w * z;

            // Update z and mu
            let fitted = &full_inputs * β
            z = y_bar + &fitted;
            mu = self.criterion.apply_link_inv(fitted);
        }

        self.parameters = Some(beta);
    }
}

/// The criterion for the Generalized Linear Model.
///
/// This trait specifies a Link function and requires a model
/// variance to be specified. The model variance must be defined
/// to specify the regression family. The other functions need not
/// be specified but can be used to control optimization.
pub trait Criterion {
	type Link : LinkFunc;

    /// The variance of the regression family.
    fn model_variance(&self, mu: f64) -> f64;

    /// Initializes the mean value.
    ///
    /// By default the mean takes the training target values.
    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        y.to_vec()
    }

    /// Computes the working weights that make up the diagonal
    /// of the `W` matrix used in the iterative reweighted least squares
    /// algorithm.
    ///
    /// This is equal to:
    ///
    /// 1 / (Var(u) * g'(u) * g'(u))
    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let grad = self.link_grad(*m);
            working_weights_vec.push(1f64 / (self.model_variance(*m) * grad * grad));
        }

        working_weights_vec
    }

    /// Computes the adjustment to the fitted values used during
    /// fitting.
    ///
    /// This is equal to:
    ///
    /// g`(u) * (y - u)
    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            y_bar_vec.push(self.link_grad(*m) * (y[idx] - m));
        }

        y_bar_vec
    }

    /// Applies the link function to a vector.
    fn apply_link_func(&self, vec: Vector<f64>) -> Vector<f64> {
        vec.apply(&Self::Link::func)
    }

    /// Applies the inverse of the link function to a vector.
    fn apply_link_inv(&self, vec: Vector<f64>) -> Vector<f64> {
    	vec.apply(&Self::Link::func_inv)
    }

    /// Computes the gradient of the link function.
    fn link_grad(&self, mu: f64) -> f64 {
        Self::Link::func_grad(mu)
    }
}

/// Link functions.
///
/// Used within Generalized Linear Regression models.
pub trait LinkFunc {
    /// The link function.
    fn func(x: f64) -> f64;

    /// The gradient of the link function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the link function.
    /// Often called the 'mean' function.
    fn func_inv(x: f64) -> f64;
}

/// The Logit link function.
///
/// Used primarily as the canonical link in Binomial Regression.
pub struct Logit;

/// The Logit link function.
///
/// g(u) = ln(x / (1 - x))
impl LinkFunc for Logit {

    fn func(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / (x * (1f64 - x))
    }

    fn func_inv(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }
}

/// The log link function.
///
/// Used primarily as the canonical link in Poisson Regression.
pub struct Log;

/// The log link function.
///
/// g(u) = ln(u)
impl LinkFunc for Log {
    fn func(x: f64) -> f64 {
        x.ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / x
    }

    fn func_inv(x: f64) -> f64 {
        x.exp()
    }
}

/// The Identity link function.
///
/// Used primarily as the canonical link in Linear Regression.
pub struct Identity;

/// The Identity link function.
///
/// g(u) = u
impl LinkFunc for Identity {
    fn func(x: f64) -> f64 {
        x
    }

    fn func_grad(_: f64) -> f64 {
        1f64
    }

    fn func_inv(x: f64) -> f64 {
        x
    }
}

/// The Bernoulli regression family.
///
/// This is equivalent to logistic regression.
pub struct Bernoulli;

impl Criterion for Bernoulli {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let var = self.model_variance(*m);

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The binomial regression family.
pub struct Binomial {
    weights: Vec<f64>,
}

impl Criterion for Binomial {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }

    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            let var = self.model_variance(*m) / self.weights[idx];

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The Normal regression family.
///
/// This is equivalent to the Linear Regression model.
pub struct Normal;

impl Criterion for Normal {
    type Link = Identity;

    fn model_variance(&self, _: f64) -> f64 {
        1f64
    }
}

/// The Poisson regression family.
pub struct Poisson;

impl Criterion for Poisson {
    type Link = Log;

    fn model_variance(&self, mu: f64) -> f64 {
        mu
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }
}<commit_msg>Adding documentation and (poor) stopping condition<commit_after>use linalg::vector::Vector;
use linalg::matrix::Matrix;

use learning::SupModel;

/// The Generalized Linear Model
///
/// The model is generic over a Criterion
/// which specifies the distribution family and
/// the link function.
pub struct GenLinearModel<C: Criterion> {
    parameters: Option<Vector<f64>>,
    criterion: C,
}

impl<C: Criterion> GenLinearModel<C> {

    /// Constructs a new Generalized Linear Model.
    ///
    /// Takes a Criterion which fully specifies the family
    /// and the link function used by the GLM.
    ///
    /// ```
    /// use rusty_machine::learning::glm::GenLinearModel;
    /// use rusty_machine::learning::glm::Bernoulli;
    ///
    /// let glm = GenLinearModel::new(Bernoulli);
    /// ```
	pub fn new(criterion: C) -> GenLinearModel<C> {
		GenLinearModel {
			parameters: None,
			criterion: criterion,
		}
	}
}

/// Supervised model trait for the GLM.
///
/// Predictions are made from the model by computing g^-1(Xb).
///
/// The model is trained using Iteratively Re-weighted Least Squares.
impl<C: Criterion> SupModel<Matrix<f64>, Vector<f64>> for GenLinearModel<C> {
    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let Some(ref v) = self.parameters {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            self.criterion.apply_link_inv(full_inputs * v)
        } else {
            panic!("The model has not been trained.");
        }
    }

    /// Train the model using inputs and targets.
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let n = inputs.rows();

        assert!(n == targets.size(),
                "Training data do not have the same dimensions.");

        // Construct initial estimate for mu
        let mut mu = Vector::new(self.criterion.initialize_mu(targets.data()));
        let mut z = mu.clone();
        let mut beta : Vector<f64> = Vector::new(vec![0f64; inputs.cols() + 1]);

        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);
        let x_t = full_inputs.transpose();

        // Iterate to convergence
        for _ in 0..8 {
            let w_diag = self.criterion.compute_working_weight(&mu.data());
            let y_bar_data = self.criterion.compute_y_bar(targets.data(), &mu.data());

            let w = Matrix::from_diag(&w_diag);
            let y_bar = Vector::new(y_bar_data);

            let x_t_w = &x_t * w;

            let new_beta = (&x_t_w * &full_inputs).inverse() * x_t_w * z;
            let diff = (beta-&new_beta).apply(&|x| x.abs()).sum();
            beta = new_beta;

            if diff < 1e-10 {
                break;
            }

            // Update z and mu
            let fitted = &full_inputs * β
            z = y_bar + &fitted;
            mu = self.criterion.apply_link_inv(fitted);
        }

        self.parameters = Some(beta);
    }
}

/// The criterion for the Generalized Linear Model.
///
/// This trait specifies a Link function and requires a model
/// variance to be specified. The model variance must be defined
/// to specify the regression family. The other functions need not
/// be specified but can be used to control optimization.
pub trait Criterion {
	type Link : LinkFunc;

    /// The variance of the regression family.
    fn model_variance(&self, mu: f64) -> f64;

    /// Initializes the mean value.
    ///
    /// By default the mean takes the training target values.
    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        y.to_vec()
    }

    /// Computes the working weights that make up the diagonal
    /// of the `W` matrix used in the iterative reweighted least squares
    /// algorithm.
    ///
    /// This is equal to:
    ///
    /// 1 / (Var(u) * g'(u) * g'(u))
    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let grad = self.link_grad(*m);
            working_weights_vec.push(1f64 / (self.model_variance(*m) * grad * grad));
        }

        working_weights_vec
    }

    /// Computes the adjustment to the fitted values used during
    /// fitting.
    ///
    /// This is equal to:
    ///
    /// g`(u) * (y - u)
    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            y_bar_vec.push(self.link_grad(*m) * (y[idx] - m));
        }

        y_bar_vec
    }

    /// Applies the link function to a vector.
    fn apply_link_func(&self, vec: Vector<f64>) -> Vector<f64> {
        vec.apply(&Self::Link::func)
    }

    /// Applies the inverse of the link function to a vector.
    fn apply_link_inv(&self, vec: Vector<f64>) -> Vector<f64> {
    	vec.apply(&Self::Link::func_inv)
    }

    /// Computes the gradient of the link function.
    fn link_grad(&self, mu: f64) -> f64 {
        Self::Link::func_grad(mu)
    }
}

/// Link functions.
///
/// Used within Generalized Linear Regression models.
pub trait LinkFunc {
    /// The link function.
    fn func(x: f64) -> f64;

    /// The gradient of the link function.
    fn func_grad(x: f64) -> f64;

    /// The inverse of the link function.
    /// Often called the 'mean' function.
    fn func_inv(x: f64) -> f64;
}

/// The Logit link function.
///
/// Used primarily as the canonical link in Binomial Regression.
pub struct Logit;

/// The Logit link function.
///
/// g(u) = ln(x / (1 - x))
impl LinkFunc for Logit {

    fn func(x: f64) -> f64 {
        (x / (1f64 - x)).ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / (x * (1f64 - x))
    }

    fn func_inv(x: f64) -> f64 {
        1.0 / (1.0 + (-x).exp())
    }
}

/// The log link function.
///
/// Used primarily as the canonical link in Poisson Regression.
pub struct Log;

/// The log link function.
///
/// g(u) = ln(u)
impl LinkFunc for Log {
    fn func(x: f64) -> f64 {
        x.ln()
    }

    fn func_grad(x: f64) -> f64 {
        1f64 / x
    }

    fn func_inv(x: f64) -> f64 {
        x.exp()
    }
}

/// The Identity link function.
///
/// Used primarily as the canonical link in Linear Regression.
pub struct Identity;

/// The Identity link function.
///
/// g(u) = u
impl LinkFunc for Identity {
    fn func(x: f64) -> f64 {
        x
    }

    fn func_grad(_: f64) -> f64 {
        1f64
    }

    fn func_inv(x: f64) -> f64 {
        x
    }
}

/// The Bernoulli regression family.
///
/// This is equivalent to logistic regression.
pub struct Bernoulli;

impl Criterion for Bernoulli {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for m in mu {
            let var = self.model_variance(*m);

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The binomial regression family.
pub struct Binomial {
    weights: Vec<f64>,
}

impl Criterion for Binomial {
    type Link = Logit;

    fn model_variance(&self, mu: f64) -> f64 {
        let var = mu * (1f64 - mu);

        if var.abs() < 1e-10 {
            1e-10
        }
        else {
            var
        }

    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else if *y_val > 1f64 - 1e-10 {
                    1f64 - 1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }

    fn compute_working_weight(&self, mu: &[f64]) -> Vec<f64> {
        let mut working_weights_vec = Vec::with_capacity(mu.len());

        for (idx, m) in mu.iter().enumerate() {
            let var = self.model_variance(*m) / self.weights[idx];

            working_weights_vec.push(if var.abs() < 1e-5 {
                1e-5
            } else {
                var
            });
        }

        working_weights_vec
    }

    fn compute_y_bar(&self, y: &[f64], mu: &[f64]) -> Vec<f64> {
        let mut y_bar_vec = Vec::with_capacity(y.len());

        for (idx, m) in mu.iter().enumerate() {
            let target_diff = y[idx] - m;

            y_bar_vec.push(if target_diff.abs() < 1e-15 {
                0f64
            } else {
                self.link_grad(*m) * target_diff
            });
        }

        y_bar_vec
    }
}

/// The Normal regression family.
///
/// This is equivalent to the Linear Regression model.
pub struct Normal;

impl Criterion for Normal {
    type Link = Identity;

    fn model_variance(&self, _: f64) -> f64 {
        1f64
    }
}

/// The Poisson regression family.
pub struct Poisson;

impl Criterion for Poisson {
    type Link = Log;

    fn model_variance(&self, mu: f64) -> f64 {
        mu
    }

    fn initialize_mu(&self, y: &[f64]) -> Vec<f64> {
        let mut mu_data = Vec::with_capacity(y.len());

        for y_val in y {
            mu_data.push(
                if *y_val < 1e-10 {
                    1e-10
                } else {
                    *y_val
                });
        }

        mu_data
    }
}<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use std::vec::Vec;

use dbus;
use dbus::{BusType, Connection, Message, NameFlag};
use dbus::arg::{Array, IterAppend};
use dbus::tree::{Access, ConnectionItem, EmitsChangedSignal, Factory, MTFn, MethodErr, MethodInfo,
                 MethodResult, PropInfo, Tree};
use uuid::Uuid;

use engine::{Engine, Pool};
use stratis::VERSION;

use super::blockdev::create_dbus_blockdev;
use super::filesystem::create_dbus_filesystem;
use super::pool::create_dbus_pool;
use super::types::{ActionQueue, DbusContext, DbusErrorEnum, DeferredAction, TData};
use super::util::{STRATIS_BASE_PATH, STRATIS_BASE_SERVICE, engine_to_dbus_err_tuple, get_next_arg,
                  msg_code_ok, msg_string_ok, tuple_to_option};

fn create_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let name: &str = get_next_arg(&mut iter, 0)?;
    let redundancy: (bool, u16) = get_next_arg(&mut iter, 1)?;
    let force: bool = get_next_arg(&mut iter, 2)?;
    let devs: Array<&str, _> = get_next_arg(&mut iter, 3)?;

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let object_path = m.path.get_name();
    let dbus_context = m.tree.get_data();
    let mut engine = dbus_context.engine.borrow_mut();
    let result = engine.create_pool(name, &blockdevs, tuple_to_option(redundancy), force);

    let return_message = message.method_return();

    let default_return: (dbus::Path, Vec<dbus::Path>) = (dbus::Path::default(), Vec::new());

    let msg = match result {
        Ok(pool_uuid) => {
            let pool_object_path: dbus::Path =
                create_dbus_pool(dbus_context, object_path.clone(), pool_uuid);

            let pool = get_mut_pool!(engine; pool_uuid; default_return; return_message);

            let bd_object_paths = pool.blockdevs()
                .iter()
                .map(|bd| create_dbus_blockdev(dbus_context, pool_object_path.clone(), bd.uuid()))
                .collect::<Vec<_>>();

            return_message.append3((pool_object_path, bd_object_paths),
                                   msg_code_ok(),
                                   msg_string_ok())
        }
        Err(x) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&x);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn destroy_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {

    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let object_path: dbus::Path<'static> = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();

    let default_return = false;
    let return_message = message.method_return();

    let pool_uuid = match m.tree.get(&object_path) {
        Some(pool_path) => get_data!(pool_path; default_return; return_message).uuid,
        None => {
            return Ok(vec![return_message.append3(default_return, msg_code_ok(), msg_string_ok())]);
        }
    };

    let msg = match dbus_context.engine.borrow_mut().destroy_pool(pool_uuid) {
        Ok(action) => {
            dbus_context
                .actions
                .borrow_mut()
                .push_remove(&object_path, m.tree);
            return_message.append3(action, msg_code_ok(), msg_string_ok())
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_version(i: &mut IterAppend, _p: &PropInfo<MTFn<TData>, TData>) -> Result<(), MethodErr> {
    i.append(VERSION);
    Ok(())
}

fn configure_simulator(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message = m.msg;
    let mut iter = message.iter_init();

    let denominator: u32 = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .configure_simulator(denominator);

    let return_message = message.method_return();

    let msg = match result {
        Ok(_) => return_message.append2(msg_code_ok(), msg_string_ok()),
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append2(rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_base_tree<'a>(dbus_context: DbusContext) -> (Tree<MTFn<TData>, TData>, dbus::Path<'a>) {

    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let create_pool_method = f.method("CreatePool", (), create_pool)
        .in_arg(("name", "s"))
        .in_arg(("redundancy", "(bq)"))
        .in_arg(("force", "b"))
        .in_arg(("devices", "as"))
        .out_arg(("result", "(oao)"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let destroy_pool_method = f.method("DestroyPool", (), destroy_pool)
        .in_arg(("pool", "o"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let configure_simulator_method = f.method("ConfigureSimulator", (), configure_simulator)
        .in_arg(("denominator", "u"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let version_property = f.property::<&str, _>("Version", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_version);

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "Manager");

    let obj_path = f.object_path(STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(f.interface(interface_name, ())
                 .add_m(create_pool_method)
                 .add_m(destroy_pool_method)
                 .add_m(configure_simulator_method)
                 .add_p(version_property));

    let path = obj_path.get_name().to_owned();
    (base_tree.add(obj_path), path)
}

/// Given an Pool, create all the needed dbus objects to represent it.
fn register_pool_dbus(dbus_context: &DbusContext, pool: &Pool, object_path: &dbus::Path<'static>) {
    let pool_path = create_dbus_pool(dbus_context, object_path.clone(), pool.uuid());
    for fs_uuid in pool.filesystems().iter().map(|f| f.uuid()) {
        create_dbus_filesystem(dbus_context, pool_path.clone(), fs_uuid);
    }
    for dev_uuid in pool.blockdevs().iter().map(|bd| bd.uuid()) {
        create_dbus_blockdev(dbus_context, pool_path.clone(), dev_uuid);
    }
}

/// Connect a stratis engine to dbus.
#[allow(type_complexity)]
pub fn connect<'a>
    (engine: Rc<RefCell<Engine>>)
     -> Result<(Connection, Tree<MTFn<TData>, TData>, dbus::Path<'a>, DbusContext), dbus::Error> {
    let c = Connection::get_private(BusType::System)?;

    let local_engine = Rc::clone(&engine);

    let (mut tree, object_path) = get_base_tree(DbusContext::new(engine));
    let dbus_context = tree.get_data().clone();

    // This should never panic as register_pool_dbus does not borrow the engine.
    for pool in local_engine.borrow().pools() {
        register_pool_dbus(&dbus_context, pool, &object_path);
    }

    tree.set_registered(&c, true)?;
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32)?;

    process_deferred_actions(&c, &mut tree, &mut dbus_context.actions.borrow_mut())?;

    Ok((c, tree, object_path, dbus_context))
}

/// Given the UUID of a pool, register all the pertinent information with dbus.
pub fn register_pool(c: &Connection,
                     engine: Rc<RefCell<Engine>>,
                     dbus_context: &DbusContext,
                     tree: &mut Tree<MTFn<TData>, TData>,
                     pool_uuid: Uuid,
                     object_path: &dbus::Path<'static>)
                     -> Result<(), dbus::Error> {

    if let Some(pool) = engine.borrow().get_pool(pool_uuid) {
        register_pool_dbus(dbus_context, pool, object_path);
        return process_deferred_actions(c, tree, &mut dbus_context.actions.borrow_mut());
    }
    Ok(())
}

/// Update the dbus tree with deferred adds and removes.
fn process_deferred_actions(c: &Connection,
                            tree: &mut Tree<MTFn<TData>, TData>,
                            actions: &mut ActionQueue)
                            -> Result<(), dbus::Error> {
    for action in actions.drain() {
        match action {
            DeferredAction::Add(path) => {
                c.register_object_path(path.get_name())?;
                tree.insert(path);
            }
            DeferredAction::Remove(path) => {
                c.unregister_object_path(&path);
                tree.remove(&path);
            }
        }
    }
    Ok(())
}

pub fn handle(c: &Connection,
              item: &ConnectionItem,
              tree: &mut Tree<MTFn<TData>, TData>,
              dbus_context: &DbusContext)
              -> Result<(), dbus::Error> {
    if let ConnectionItem::MethodCall(ref msg) = *item {
        if let Some(v) = tree.handle(msg) {
            // Probably the wisest is to ignore any send errors here -
            // maybe the remote has disconnected during our processing.
            for m in v {
                let _ = c.send(m);
            }
        }

        process_deferred_actions(c, tree, &mut dbus_context.actions.borrow_mut())?;
    }

    Ok(())
}
<commit_msg>api.rs: Correct use for ConnectionItem<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use std::vec::Vec;

use dbus;
use dbus::{BusType, Connection, ConnectionItem, Message, NameFlag};
use dbus::arg::{Array, IterAppend};
use dbus::tree::{Access, EmitsChangedSignal, Factory, MTFn, MethodErr, MethodInfo, MethodResult,
                 PropInfo, Tree};
use uuid::Uuid;

use engine::{Engine, Pool};
use stratis::VERSION;

use super::blockdev::create_dbus_blockdev;
use super::filesystem::create_dbus_filesystem;
use super::pool::create_dbus_pool;
use super::types::{ActionQueue, DbusContext, DbusErrorEnum, DeferredAction, TData};
use super::util::{STRATIS_BASE_PATH, STRATIS_BASE_SERVICE, engine_to_dbus_err_tuple, get_next_arg,
                  msg_code_ok, msg_string_ok, tuple_to_option};

fn create_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let name: &str = get_next_arg(&mut iter, 0)?;
    let redundancy: (bool, u16) = get_next_arg(&mut iter, 1)?;
    let force: bool = get_next_arg(&mut iter, 2)?;
    let devs: Array<&str, _> = get_next_arg(&mut iter, 3)?;

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let object_path = m.path.get_name();
    let dbus_context = m.tree.get_data();
    let mut engine = dbus_context.engine.borrow_mut();
    let result = engine.create_pool(name, &blockdevs, tuple_to_option(redundancy), force);

    let return_message = message.method_return();

    let default_return: (dbus::Path, Vec<dbus::Path>) = (dbus::Path::default(), Vec::new());

    let msg = match result {
        Ok(pool_uuid) => {
            let pool_object_path: dbus::Path =
                create_dbus_pool(dbus_context, object_path.clone(), pool_uuid);

            let pool = get_mut_pool!(engine; pool_uuid; default_return; return_message);

            let bd_object_paths = pool.blockdevs()
                .iter()
                .map(|bd| create_dbus_blockdev(dbus_context, pool_object_path.clone(), bd.uuid()))
                .collect::<Vec<_>>();

            return_message.append3((pool_object_path, bd_object_paths),
                                   msg_code_ok(),
                                   msg_string_ok())
        }
        Err(x) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&x);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn destroy_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {

    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let object_path: dbus::Path<'static> = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();

    let default_return = false;
    let return_message = message.method_return();

    let pool_uuid = match m.tree.get(&object_path) {
        Some(pool_path) => get_data!(pool_path; default_return; return_message).uuid,
        None => {
            return Ok(vec![return_message.append3(default_return, msg_code_ok(), msg_string_ok())]);
        }
    };

    let msg = match dbus_context.engine.borrow_mut().destroy_pool(pool_uuid) {
        Ok(action) => {
            dbus_context
                .actions
                .borrow_mut()
                .push_remove(&object_path, m.tree);
            return_message.append3(action, msg_code_ok(), msg_string_ok())
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_version(i: &mut IterAppend, _p: &PropInfo<MTFn<TData>, TData>) -> Result<(), MethodErr> {
    i.append(VERSION);
    Ok(())
}

fn configure_simulator(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message = m.msg;
    let mut iter = message.iter_init();

    let denominator: u32 = get_next_arg(&mut iter, 0)?;

    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .configure_simulator(denominator);

    let return_message = message.method_return();

    let msg = match result {
        Ok(_) => return_message.append2(msg_code_ok(), msg_string_ok()),
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err_tuple(&err);
            return_message.append2(rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_base_tree<'a>(dbus_context: DbusContext) -> (Tree<MTFn<TData>, TData>, dbus::Path<'a>) {

    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let create_pool_method = f.method("CreatePool", (), create_pool)
        .in_arg(("name", "s"))
        .in_arg(("redundancy", "(bq)"))
        .in_arg(("force", "b"))
        .in_arg(("devices", "as"))
        .out_arg(("result", "(oao)"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let destroy_pool_method = f.method("DestroyPool", (), destroy_pool)
        .in_arg(("pool", "o"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let configure_simulator_method = f.method("ConfigureSimulator", (), configure_simulator)
        .in_arg(("denominator", "u"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let version_property = f.property::<&str, _>("Version", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_version);

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "Manager");

    let obj_path = f.object_path(STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(f.interface(interface_name, ())
                 .add_m(create_pool_method)
                 .add_m(destroy_pool_method)
                 .add_m(configure_simulator_method)
                 .add_p(version_property));

    let path = obj_path.get_name().to_owned();
    (base_tree.add(obj_path), path)
}

/// Given an Pool, create all the needed dbus objects to represent it.
fn register_pool_dbus(dbus_context: &DbusContext, pool: &Pool, object_path: &dbus::Path<'static>) {
    let pool_path = create_dbus_pool(dbus_context, object_path.clone(), pool.uuid());
    for fs_uuid in pool.filesystems().iter().map(|f| f.uuid()) {
        create_dbus_filesystem(dbus_context, pool_path.clone(), fs_uuid);
    }
    for dev_uuid in pool.blockdevs().iter().map(|bd| bd.uuid()) {
        create_dbus_blockdev(dbus_context, pool_path.clone(), dev_uuid);
    }
}

/// Connect a stratis engine to dbus.
#[allow(type_complexity)]
pub fn connect<'a>
    (engine: Rc<RefCell<Engine>>)
     -> Result<(Connection, Tree<MTFn<TData>, TData>, dbus::Path<'a>, DbusContext), dbus::Error> {
    let c = Connection::get_private(BusType::System)?;

    let local_engine = Rc::clone(&engine);

    let (mut tree, object_path) = get_base_tree(DbusContext::new(engine));
    let dbus_context = tree.get_data().clone();

    // This should never panic as register_pool_dbus does not borrow the engine.
    for pool in local_engine.borrow().pools() {
        register_pool_dbus(&dbus_context, pool, &object_path);
    }

    tree.set_registered(&c, true)?;
    c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32)?;

    process_deferred_actions(&c, &mut tree, &mut dbus_context.actions.borrow_mut())?;

    Ok((c, tree, object_path, dbus_context))
}

/// Given the UUID of a pool, register all the pertinent information with dbus.
pub fn register_pool(c: &Connection,
                     engine: Rc<RefCell<Engine>>,
                     dbus_context: &DbusContext,
                     tree: &mut Tree<MTFn<TData>, TData>,
                     pool_uuid: Uuid,
                     object_path: &dbus::Path<'static>)
                     -> Result<(), dbus::Error> {

    if let Some(pool) = engine.borrow().get_pool(pool_uuid) {
        register_pool_dbus(dbus_context, pool, object_path);
        return process_deferred_actions(c, tree, &mut dbus_context.actions.borrow_mut());
    }
    Ok(())
}

/// Update the dbus tree with deferred adds and removes.
fn process_deferred_actions(c: &Connection,
                            tree: &mut Tree<MTFn<TData>, TData>,
                            actions: &mut ActionQueue)
                            -> Result<(), dbus::Error> {
    for action in actions.drain() {
        match action {
            DeferredAction::Add(path) => {
                c.register_object_path(path.get_name())?;
                tree.insert(path);
            }
            DeferredAction::Remove(path) => {
                c.unregister_object_path(&path);
                tree.remove(&path);
            }
        }
    }
    Ok(())
}

pub fn handle(c: &Connection,
              item: &ConnectionItem,
              tree: &mut Tree<MTFn<TData>, TData>,
              dbus_context: &DbusContext)
              -> Result<(), dbus::Error> {
    if let ConnectionItem::MethodCall(ref msg) = *item {
        if let Some(v) = tree.handle(msg) {
            // Probably the wisest is to ignore any send errors here -
            // maybe the remote has disconnected during our processing.
            for m in v {
                let _ = c.send(m);
            }
        }

        process_deferred_actions(c, tree, &mut dbus_context.actions.borrow_mut())?;
    }

    Ok(())
}
<|endoftext|>


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

//! An "interner" is a data structure that associates values with uint tags and
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.

use ast::Name;

use std::collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::mem;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

/// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = Name(self.len() as u32);
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    /// Create a gensym with the same name as an existing
    /// entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx.uint())).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx.uint())).clone()
    }

    /// Returns this string with lifetime tied to the interner. Since
    /// strings may never be removed from the interner, this is safe.
    pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str {
        let vect = self.vect.borrow();
        let s: &str = vect.get(idx.uint()).as_slice();
        unsafe {
            mem::transmute(s)
        }
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

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

    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(Name(13));
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), Name(4));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(Name(0)), RcStr::new("Alan"));
        assert_eq!(i.get(Name(1)), RcStr::new("Bob"));
        assert_eq!(i.get(Name(2)), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), Name(1));
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern("cat"), Name(1));
        assert_eq!(i.intern("cat"), Name(1));
        // dog is still at zero
        assert_eq!(i.intern("dog"), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), Name(4));
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(Name(2)), Name(5));
        assert_eq!(i.get(Name(5)), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(Name(2)), Name(6));
        assert_eq!(i.get(Name(6)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }
}
<commit_msg>auto merge of #17221 : bkoropoff/rust/strinterner-unsafe, r=sfackler<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An "interner" is a data structure that associates values with uint tags and
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.

use ast::Name;

use std::collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = Name((*vect).len() as u32);
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

/// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = Name(self.len() as u32);
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    /// Create a gensym with the same name as an existing
    /// entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = Name(self.len() as u32);
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx.uint())).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx.uint())).clone()
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

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

    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(Name(13));
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        assert_eq!(i.intern(RcStr::new("cat")), Name(1));
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), Name(4));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(Name(0)), RcStr::new("Alan"));
        assert_eq!(i.get(Name(1)), RcStr::new("Bob"));
        assert_eq!(i.get(Name(2)), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), Name(1));
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), Name(0));
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), Name(0));
        // different string gets a different #:
        assert_eq!(i.intern("cat"), Name(1));
        assert_eq!(i.intern("cat"), Name(1));
        // dog is still at zero
        assert_eq!(i.intern("dog"), Name(0));
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), Name(2));
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), Name(3));
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), Name(4));
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(Name(2)), Name(5));
        assert_eq!(i.get(Name(5)), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(Name(2)), Name(6));
        assert_eq!(i.get(Name(6)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(0)), RcStr::new("dog"));
        assert_eq!(i.get(Name(1)), RcStr::new("cat"));
        assert_eq!(i.get(Name(2)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(3)), RcStr::new("zebra"));
        assert_eq!(i.get(Name(4)), RcStr::new("dog"));
    }
}
<|endoftext|>


<commit_before>use hyper::version::HttpVersion;

pub fn is_valid_http_version(v: HttpVersion) -> bool {
    v >= HttpVersion::Http11
}
<commit_msg>Add doc-test<commit_after>use hyper::version::HttpVersion;

/// Check the given HttpVersion.
///
/// This version should be at least 1.1 to allow chunks downloading.
///
/// # Examples
///
/// ```
/// extern crate hyper;
/// extern crate snatch;
///
/// fn main() {
///     use hyper::version::HttpVersion;
///     use snatch::http_version::is_valid_http_version;
///
///     is_valid_http_version(HttpVersion::Http11);
/// }
/// ```
///
pub fn is_valid_http_version(v: HttpVersion) -> bool {
    v >= HttpVersion::Http11
}
<|endoftext|>


<commit_before>#[cfg(feature = "with-serde")]
extern crate serde;
#[cfg(feature = "with-serde")]
extern crate serde_json;
#[cfg(feature = "with-serde")]
#[macro_use]
extern crate serde_derive;

extern crate ipnetwork;

#[cfg(test)]
mod tests {

    use ipnetwork::{Ipv4Network, Ipv6Network};
    use std::net::{Ipv4Addr, Ipv6Addr};

    #[cfg(feature = "with-serde")]
    #[test]
    fn test_ipv4_json() {
        let json_string = r#"{"ipnetwork":{"addr":"127.1.0.0","prefix":24}}"#;

        #[derive(Serialize, Deserialize)]
        struct MyStruct {
            ipnetwork: Ipv4Network,
        }

        let mystruct: MyStruct = ::serde_json::from_str(json_string).unwrap();

        assert_eq!(mystruct.ipnetwork.ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(mystruct.ipnetwork.prefix(), 24);

        assert_eq!(::serde_json::to_string(&mystruct).unwrap(), json_string);
    }

    #[cfg(feature = "with-serde")]
    #[test]
    fn test_ipv6_json() {
        let json_string = r#"{"ipnetwork":{"addr":"::1","prefix":0}}"#;

        #[derive(Serialize, Deserialize)]
        struct MyStruct {
            ipnetwork: Ipv6Network,
        }

        let mystruct: MyStruct = ::serde_json::from_str(json_string).unwrap();

        assert_eq!(mystruct.ipnetwork.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(mystruct.ipnetwork.prefix(), 0);

        assert_eq!(::serde_json::to_string(&mystruct).unwrap(), json_string);
    }
}<commit_msg>vector of ip networks<commit_after>#[cfg(feature = "with-serde")]
extern crate serde;
#[cfg(feature = "with-serde")]
extern crate serde_json;
#[cfg(feature = "with-serde")]
#[macro_use]
extern crate serde_derive;

extern crate ipnetwork;

#[cfg(test)]
mod tests {

    use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
    use std::net::{Ipv4Addr, Ipv6Addr};

    #[cfg(feature = "with-serde")]
    #[test]
    fn test_ipv4_json() {
        let json_string = r#"{"ipnetwork":{"addr":"127.1.0.0","prefix":24}}"#;

        #[derive(Serialize, Deserialize)]
        struct MyStruct {
            ipnetwork: Ipv4Network,
        }

        let mystruct: MyStruct = ::serde_json::from_str(json_string).unwrap();

        assert_eq!(mystruct.ipnetwork.ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(mystruct.ipnetwork.prefix(), 24);

        assert_eq!(::serde_json::to_string(&mystruct).unwrap(), json_string);
    }

    #[cfg(feature = "with-serde")]
    #[test]
    fn test_ipv6_json() {
        let json_string = r#"{"ipnetwork":{"addr":"::1","prefix":0}}"#;

        #[derive(Serialize, Deserialize)]
        struct MyStruct {
            ipnetwork: Ipv6Network,
        }

        let mystruct: MyStruct = ::serde_json::from_str(json_string).unwrap();

        assert_eq!(mystruct.ipnetwork.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(mystruct.ipnetwork.prefix(), 0);

        assert_eq!(::serde_json::to_string(&mystruct).unwrap(), json_string);
    }

    #[cfg(feature = "with-serde")]
    #[test]
    fn test_ipnetwork_json() {
        let json_string = r#"{"ipnetwork":[{"V4":{"addr":"127.1.0.0","prefix":24}},{"V6":{"addr":"::1","prefix":0}}]}"#;

        #[derive(Serialize, Deserialize)]
        struct MyStruct {
            ipnetwork: Vec<IpNetwork>,
        }

        let mystruct: MyStruct = ::serde_json::from_str(json_string).unwrap();

        assert_eq!(mystruct.ipnetwork[0].ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(mystruct.ipnetwork[0].prefix(), 24);
        assert_eq!(mystruct.ipnetwork[1].ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(mystruct.ipnetwork[1].prefix(), 0);

        assert_eq!(::serde_json::to_string(&mystruct).unwrap(), json_string);
    }
}<|endoftext|>


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

use failure::SyncFailure;
use handlebars::Handlebars;
use serde_json::Value;

use export_docker::Result;

use manifest::Manifest;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");
const BINDFILE: &'static str = include_str!("../defaults/KubernetesBind.hbs");

pub struct ManifestJson {
    pub main: Value,
    pub binds: Vec<Value>,
}

impl ManifestJson {
    pub fn new(manifest: &Manifest) -> Self {
        let main = json!({
            "metadata_name": manifest.metadata_name,
            "habitat_name": manifest.habitat_name,
            "image": manifest.image,
            "count": manifest.count,
            "service_topology": manifest.service_topology.to_string(),
            "service_group": manifest.service_group,
            "config": manifest.config,
            "ring_secret_name": manifest.ring_secret_name,
            "bind": !manifest.binds.is_empty()
        });

        let mut binds = Vec::new();
        for bind in &manifest.binds {
            let json = json!({
                "name": bind.name.clone(),
                "service": bind.service.clone(),
                "group": bind.group.clone(),
            });

            binds.push(json);
        }

        ManifestJson {
            main: main,
            binds: binds,
        }
    }

    // TODO: Implement TryInto trait instead when it's in stable std crate
    pub fn into_string(&self) -> Result<String> {
        let r = Handlebars::new()
            .template_render(MANIFESTFILE, &self.main)
            .map_err(SyncFailure::new)?;
        let mut s = r.lines().filter(|l| *l != "").collect::<Vec<_>>().join(
            "\n",
        ) + "\n";

        for bind in &self.binds {
            s += &Handlebars::new().template_render(BINDFILE, &bind).map_err(
                SyncFailure::new,
            )?;
        }

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

use failure::SyncFailure;
use handlebars::Handlebars;
use serde_json::Value;

use export_docker::Result;

use manifest::Manifest;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");
const BINDFILE: &'static str = include_str!("../defaults/KubernetesBind.hbs");

/// Represents the [`Manifest`] in JSON format. This is an intermediate type that can be converted
/// to the final manifest YAML file content, ready for consumption by a Kubernetes cluster.
///
/// The reason for the existence of this intermediate type is to allow users of this crate to be
/// able to modify the JSON before converting it to the final manifest string.
///
/// [`Manifest`]: ../manifest/struct.Manifest.html
pub struct ManifestJson {
    /// JSON object, holding values for the main body of the YAML content.
    pub main: Value,
    /// JSON representations of [`Bind`] instances.
    ///
    /// [`Bind`]: ../bind/struct.Bind.html
    pub binds: Vec<Value>,
}

impl ManifestJson {
    /// Create a `ManifestJson` from `manifest`.
    pub fn new(manifest: &Manifest) -> Self {
        let main = json!({
            "metadata_name": manifest.metadata_name,
            "habitat_name": manifest.habitat_name,
            "image": manifest.image,
            "count": manifest.count,
            "service_topology": manifest.service_topology.to_string(),
            "service_group": manifest.service_group,
            "config": manifest.config,
            "ring_secret_name": manifest.ring_secret_name,
            "bind": !manifest.binds.is_empty()
        });

        let mut binds = Vec::new();
        for bind in &manifest.binds {
            let json = json!({
                "name": bind.name.clone(),
                "service": bind.service.clone(),
                "group": bind.group.clone(),
            });

            binds.push(json);
        }

        ManifestJson {
            main: main,
            binds: binds,
        }
    }

    /// Convert into a string. The returned string is the final manifest YAML file content, ready
    /// for consumption by a Kubernetes cluster.
    ///
    /// # Errors
    ///
    /// * Rendering from the template fails. This can only happen if the template has a syntax
    /// error or the command-line arguments are incorrectly formatted. In both cases, it's a
    /// most likely a programmer error if it happens.
    // TODO: Implement TryInto trait instead when it's in stable std crate
    pub fn into_string(&self) -> Result<String> {
        let r = Handlebars::new()
            .template_render(MANIFESTFILE, &self.main)
            .map_err(SyncFailure::new)?;
        let mut s = r.lines().filter(|l| *l != "").collect::<Vec<_>>().join(
            "\n",
        ) + "\n";

        for bind in &self.binds {
            s += &Handlebars::new().template_render(BINDFILE, &bind).map_err(
                SyncFailure::new,
            )?;
        }

        Ok(s)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-color")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-style")}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}"
    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: ${side},
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = self.border_${side}_width.clone();
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(specified::CSSColor,
                            specified::BorderStyle,
                            specified::BorderWidth), ()> {
    use values::specified::{CSSColor, BorderStyle, BorderWidth};
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any {
        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
            style.unwrap_or(BorderStyle::none),
            width.unwrap_or(BorderWidth::Medium)))
    } else {
        Err(())
    }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand
        name="border-${side}"
        sub_properties="${' '.join(
            'border-%s-%s' % (side, prop)
            for prop in ['color', 'style', 'width']
        )}"
        alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}"
        spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width.clone(),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let all_equal = {
                % for side in PHYSICAL_SIDES:
                  let border_${side}_width = self.border_${side}_width;
                  let border_${side}_style = self.border_${side}_style;
                  let border_${side}_color = self.border_${side}_color;
                % endfor

                border_top_width == border_right_width &&
                border_right_width == border_bottom_width &&
                border_bottom_width == border_left_width &&

                border_top_style == border_right_style &&
                border_right_style == border_bottom_style &&
                border_bottom_style == border_left_style &&

                border_top_color == border_right_color &&
                border_right_color == border_bottom_color &&
                border_bottom_color == border_left_color
            };

            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            if all_equal {
                super::serialize_directional_border(
                    dest,
                    self.border_${side}_width,
                    self.border_${side}_style,
                    self.border_${side}_color
                )
            } else {
                Ok(())
            }
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: radii.top_left,
            border_top_right_radius: radii.top_right,
            border_bottom_right_radius: radii.bottom_right,
            border_bottom_left_radius: radii.bottom_left,
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            Ok((w, o))
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: border_image_${name},
            % endfor
         })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.border_image_source.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_slice.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_width.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_outset.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_repeat.to_css(dest)
        }
    }
</%helpers:shorthand>
<commit_msg>border-image no more accepting shorthand values<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>

${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-color")}

${helpers.four_sides_shorthand("border-style", "border-%s-style",
                               "specified::BorderStyle::parse",
                               spec="https://drafts.csswg.org/css-backgrounds/#border-style")}

<%helpers:shorthand name="border-width" sub_properties="${
        ' '.join('border-%s-width' % side
                 for side in ['top', 'right', 'bottom', 'left'])}"
    spec="https://drafts.csswg.org/css-backgrounds/#border-width">
    use super::parse_four_sides;
    use parser::Parse;
    use values::specified;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                ${to_rust_ident('border-%s-width' % side)}: ${side},
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            % for side in ["top", "right", "bottom", "left"]:
                let ${side} = self.border_${side}_width.clone();
            % endfor

            super::serialize_four_sides(dest, &top, &right, &bottom, &left)
        }
    }
</%helpers:shorthand>

pub fn parse_border(context: &ParserContext, input: &mut Parser)
                 -> Result<(specified::CSSColor,
                            specified::BorderStyle,
                            specified::BorderWidth), ()> {
    use values::specified::{CSSColor, BorderStyle, BorderWidth};
    let _unused = context;
    let mut color = None;
    let mut style = None;
    let mut width = None;
    let mut any = false;
    loop {
        if color.is_none() {
            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
                color = Some(value);
                any = true;
                continue
            }
        }
        if style.is_none() {
            if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                style = Some(value);
                any = true;
                continue
            }
        }
        if width.is_none() {
            if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
                width = Some(value);
                any = true;
                continue
            }
        }
        break
    }
    if any {
        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
            style.unwrap_or(BorderStyle::none),
            width.unwrap_or(BorderWidth::Medium)))
    } else {
        Err(())
    }
}

% for side, logical in ALL_SIDES:
    <%
        spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
        if logical:
            spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
    %>
    <%helpers:shorthand
        name="border-${side}"
        sub_properties="${' '.join(
            'border-%s-%s' % (side, prop)
            for prop in ['color', 'style', 'width']
        )}"
        alias="${maybe_moz_logical_alias(product, (side, logical), '-moz-border-%s')}"
        spec="${spec}">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            border_${to_rust_ident(side)}_color: color,
            border_${to_rust_ident(side)}_style: style,
            border_${to_rust_ident(side)}_width: width
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            super::serialize_directional_border(
                dest,
                self.border_${to_rust_ident(side)}_width,
                self.border_${to_rust_ident(side)}_style,
                self.border_${to_rust_ident(side)}_color
            )
        }
    }

    </%helpers:shorthand>
% endfor

<%helpers:shorthand name="border" sub_properties="${' '.join(
    'border-%s-%s' % (side, prop)
    for side in ['top', 'right', 'bottom', 'left']
    for prop in ['color', 'style', 'width']
)}" spec="https://drafts.csswg.org/css-backgrounds/#border">

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let (color, style, width) = try!(super::parse_border(context, input));
        Ok(Longhands {
            % for side in ["top", "right", "bottom", "left"]:
                border_${side}_color: color.clone(),
                border_${side}_style: style,
                border_${side}_width: width.clone(),
            % endfor
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let all_equal = {
                % for side in PHYSICAL_SIDES:
                  let border_${side}_width = self.border_${side}_width;
                  let border_${side}_style = self.border_${side}_style;
                  let border_${side}_color = self.border_${side}_color;
                % endfor

                border_top_width == border_right_width &&
                border_right_width == border_bottom_width &&
                border_bottom_width == border_left_width &&

                border_top_style == border_right_style &&
                border_right_style == border_bottom_style &&
                border_bottom_style == border_left_style &&

                border_top_color == border_right_color &&
                border_right_color == border_bottom_color &&
                border_bottom_color == border_left_color
            };

            // If all longhands are all present, then all sides should be the same,
            // so we can just one set of color/style/width
            if all_equal {
                super::serialize_directional_border(
                    dest,
                    self.border_${side}_width,
                    self.border_${side}_style,
                    self.border_${side}_color
                )
            } else {
                Ok(())
            }
        }
    }

</%helpers:shorthand>

<%helpers:shorthand name="border-radius" sub_properties="${' '.join(
    'border-%s-radius' % (corner)
     for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
    use values::specified::basic_shape::BorderRadius;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let radii = try!(BorderRadius::parse(context, input));
        Ok(Longhands {
            border_top_left_radius: radii.top_left,
            border_top_right_radius: radii.top_right,
            border_bottom_right_radius: radii.bottom_right,
            border_bottom_left_radius: radii.bottom_left,
        })
    }

    // TODO: I do not understand how border radius works with respect to the slashes /,
    // so putting a default generic impl for now
    // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.border_top_left_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_top_right_radius.to_css(dest));
            try!(write!(dest, " "));

            try!(self.border_bottom_right_radius.to_css(dest));
            try!(write!(dest, " "));

            self.border_bottom_left_radius.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="border-image" sub_properties="border-image-outset
    border-image-repeat border-image-slice border-image-source border-image-width"
    extra_prefixes="moz webkit" spec="https://drafts.csswg.org/css-backgrounds-3/#border-image">
    use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
    use properties::longhands::{border_image_source, border_image_width};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        % for name in "outset repeat slice source width".split():
            let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
        % endfor

        try!(input.try(|input| {
            % for name in "outset repeat slice source width".split():
                let mut ${name} = None;
            % endfor
            loop {
                if slice.is_none() {
                    if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
                        slice = Some(value);
                        // Parse border image width and outset, if applicable.
                        let maybe_width_outset: Result<_, ()> = input.try(|input| {
                            try!(input.expect_delim('/'));

                            // Parse border image width, if applicable.
                            let w = input.try(|input|
                                border_image_width::parse(context, input)).ok();

                            // Parse border image outset if applicable.
                            let o = input.try(|input| {
                                try!(input.expect_delim('/'));
                                border_image_outset::parse(context, input)
                            }).ok();
                            if w.is_none() && o.is_none() {
                               Err(())
                            }
                            else {
                               Ok((w, o))
                            }
                        });
                        if let Ok((w, o)) = maybe_width_outset {
                            width = w;
                            outset = o;
                        }

                        continue
                    }
                }
                % for name in "source repeat".split():
                    if ${name}.is_none() {
                        if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
                            ${name} = Some(value);
                            continue
                        }
                    }
                % endfor
                break
            }
            let mut any = false;
            % for name in "outset repeat slice source width".split():
                any = any || ${name}.is_some();
            % endfor
            if any {
                % for name in "outset repeat slice source width".split():
                    if let Some(b_${name}) = ${name} {
                        border_image_${name} = b_${name};
                    }
                % endfor
                Ok(())
            } else {
                Err(())
            }
        }));

        Ok(Longhands {
            % for name in "outset repeat slice source width".split():
                border_image_${name}: border_image_${name},
            % endfor
         })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.border_image_source.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_slice.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_width.to_css(dest)?;
            dest.write_str(" / ")?;
            self.border_image_outset.to_css(dest)?;
            dest.write_str(" ")?;
            self.border_image_repeat.to_css(dest)
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>use crate::syntax::ident;
use std::fmt::{self, Display};
use syn::parse::{Parse, ParseStream, Result};
use syn::{Path, Token};

mod kw {
    syn::custom_keyword!(namespace);
}

pub struct Namespace {
    segments: Vec<String>,
}

impl Parse for Namespace {
    fn parse(input: ParseStream) -> Result<Self> {
        let mut segments = Vec::new();
        if !input.is_empty() {
            input.parse::<kw::namespace>()?;
            input.parse::<Token![=]>()?;
            let path = input.call(Path::parse_mod_style)?;
            for segment in path.segments {
                ident::check(&segment.ident)?;
                segments.push(segment.ident.to_string());
            }
            input.parse::<Option<Token![,]>>()?;
        }
        Ok(Namespace { segments })
    }
}

impl Display for Namespace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for segment in &self.segments {
            f.write_str(segment)?;
            f.write_str("$")?;
        }
        Ok(())
    }
}
<commit_msg>Enable Namespace to be used in format_ident<commit_after>use crate::syntax::ident;
use quote::IdentFragment;
use std::fmt::{self, Display};
use syn::parse::{Parse, ParseStream, Result};
use syn::{Path, Token};

mod kw {
    syn::custom_keyword!(namespace);
}

pub struct Namespace {
    segments: Vec<String>,
}

impl Parse for Namespace {
    fn parse(input: ParseStream) -> Result<Self> {
        let mut segments = Vec::new();
        if !input.is_empty() {
            input.parse::<kw::namespace>()?;
            input.parse::<Token![=]>()?;
            let path = input.call(Path::parse_mod_style)?;
            for segment in path.segments {
                ident::check(&segment.ident)?;
                segments.push(segment.ident.to_string());
            }
            input.parse::<Option<Token![,]>>()?;
        }
        Ok(Namespace { segments })
    }
}

impl Display for Namespace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for segment in &self.segments {
            f.write_str(segment)?;
            f.write_str("$")?;
        }
        Ok(())
    }
}

impl IdentFragment for Namespace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self, f)
    }
}
<|endoftext|>