<commit_before>// Edge Operation L-System Genome

pub mod edgeop;
mod expr_op;
mod cond_op;

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::{self, FitnessEval, Mate, MultiObjective3};
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use rand::distributions::range::Range;
use graph_annealing::owned_weighted_choice::OwnedWeightedChoice;
use graph_annealing::fitness_function::FitnessFunction;
use graph_annealing::goal::Goal;
use std::str::FromStr;
use triadic_census::OptDenseDigraph;
use lindenmayer_system::{Alphabet, Condition, Symbol, SymbolString, System};
use lindenmayer_system::symbol::Sym2;
use lindenmayer_system::expr::Expr;
use self::edgeop::{EdgeOp, edgeops_to_graph};
use self::expr_op::{ConstExprOp, ExprOp, random_const_expr, random_expr};
use self::cond_op::{CondOp, random_cond};
use simple_parallel::Pool;
use crossbeam;

/// Element-wise Mutation operation.
defops!{MutOp;
    // No mutation (copy element)
    Copy,
    // Insert new operation
    Insert,
    // Remove an operation
    Remove,
    // Modify the operation
    ModifyOp,
    // Modify a parameter value
    ModifyParam,
    // Modify both operation and parameter
    Replace
}

/// Variation operators
defops!{VarOp;
    // No variation. Reproduce exactly
    Copy,

    // Mutate
    Mutate,

    // 2-point Linear crossover
    LinearCrossover2,

    // Uniform crossover
    UniformCrossover
}

// The alphabet of terminal and non-terminals we use.
// Non-terminals are our rules, while terminals are the EdgeOps.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum EdgeAlphabet {
    Terminal(EdgeOp),
    NonTerminal(u32),
}

impl Alphabet for EdgeAlphabet {}

// We use 2-ary symbols, i.e. symbols with two parameters.
type Sym = Sym2<EdgeAlphabet, f32>;

pub struct SymbolGenerator {
    pub max_expr_depth: usize,
    pub expr_weighted_op: OwnedWeightedChoice<ExprOp>,
    pub expr_weighted_op_max_depth: OwnedWeightedChoice<ExprOp>,

    // terminal symbols
    pub edge_weighted_op: OwnedWeightedChoice<EdgeOp>,

    pub nonterminal_symbols: Range<u32>,

    /// The probability with which a terminal value is choosen.
    pub prob_terminal: Probability,

    pub const_expr_weighted_op: OwnedWeightedChoice<ConstExprOp>,
}

impl SymbolGenerator {
    /// Generates a random production (right hand-side of a rule).
    pub fn gen_symbolstring<R, S>(&self,
                                  rng: &mut R,
                                  len: usize,
                                  arity: usize,
                                  num_params: usize)
                                  -> SymbolString<S>
        where R: Rng,
              S: Symbol<A = EdgeAlphabet, T = f32>
    {
        SymbolString((0..len)
                         .into_iter()
                         .map(|_| self.gen_symbol(rng, arity, num_params))
                         .collect())
    }

    pub fn gen_symbol<R, S>(&self, rng: &mut R, arity: usize, num_params: usize) -> S
        where R: Rng,
              S: Symbol<A = EdgeAlphabet, T = f32>
    {
        S::from_iter(self.gen_symbol_value(rng),
                     (0..arity).into_iter().map(|_| self.gen_expr(rng, num_params)))

    }

    fn gen_expr<R: Rng>(&self, rng: &mut R, num_params: usize) -> Expr<f32> {
        random_expr(rng,
                    num_params,
                    self.max_expr_depth,
                    &self.expr_weighted_op,
                    &self.expr_weighted_op_max_depth)
    }

    fn gen_terminal<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        EdgeAlphabet::Terminal(self.edge_weighted_op.ind_sample(rng))
    }

    pub fn gen_nonterminal<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        EdgeAlphabet::NonTerminal(self.nonterminal_symbols.ind_sample(rng))
    }

    fn gen_symbol_value<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_terminal) {
            self.gen_terminal(rng)
        } else {
            self.gen_nonterminal(rng)
        }
    }

    /// Generate a simple condition like:
    ///     Arg(n) or 0.0 [>=] or [<=] constant expr
    fn gen_simple_rule_condition<R: Rng>(&self, rng: &mut R, arity: usize) -> Condition<f32> {
        let lhs = if arity > 0 {
            Expr::Arg(rng.gen_range(0, arity))
        } else {
            Expr::Const(0.0)
        };

        let rhs = random_const_expr(rng, &self.const_expr_weighted_op);

        if rng.gen::<bool>() {
            Condition::GreaterEqual(Box::new(lhs), Box::new(rhs))
        } else {
            Condition::LessEqual(Box::new(lhs), Box::new(rhs))
        }
    }

    // Generate a random rule with `symbol` and `arity` parameters.
    //
    // fn gen_rule<R: Rng>(&self, symbol: EdgeAlphabet, arity: usize) {
    // }
}

// When we need a value within (0, 1], we simply cut off the integer part.
// Max depth.

// # Genome interpretation:
//
//     * We use rule with number 0 as axiom.
//       The arguments for the axiom are fixed and passed in from the command line.
//       For simplicity, these arguments are duplicated in each Genome in `axiom_params`.
//       One could also apply genetic operations onto these.
//
//
#[derive(Clone, Debug)]
pub struct Genome {
    system: System<Sym>,
}

pub struct Toolbox<N, E> {
    goal: Goal<N, E>,
    pool: Pool,
    fitness_functions: (FitnessFunction, FitnessFunction, FitnessFunction),

    weighted_op: OwnedWeightedChoice<EdgeOp>,
    weighted_var_op: OwnedWeightedChoice<VarOp>,
    weighted_mut_op: OwnedWeightedChoice<MutOp>,
    prob_mutate_elem: Probability,

    /// Arguments to the axiom rule.
    pub axiom_args: Vec<Expr<f32>>,

    /// Maximum number of iterations of the L-system  (XXX: Limit also based on generated length)
    pub iterations: usize,
}

impl<N: Clone + Default, E: Clone + Default> Toolbox<N, E> {
    pub fn new(goal: Goal<N, E>,
               pool: Pool,
               fitness_functions: (FitnessFunction, FitnessFunction, FitnessFunction),
               weighted_op: Vec<Weighted<EdgeOp>>,
               weighted_var_op: Vec<Weighted<VarOp>>,
               weighted_mut_op: Vec<Weighted<MutOp>>,
               prob_mutate_elem: Probability)
               -> Toolbox<N, E> {

        Toolbox {
            goal: goal,
            pool: pool,
            fitness_functions: fitness_functions,
            prob_mutate_elem: prob_mutate_elem,
            weighted_op: OwnedWeightedChoice::new(weighted_op),
            weighted_var_op: OwnedWeightedChoice::new(weighted_var_op),
            weighted_mut_op: OwnedWeightedChoice::new(weighted_mut_op),
            axiom_args: vec![],
            iterations: 10,
        }
    }

    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &Genome) -> Genome {
        // let mut mut_ind = Vec::with_capacity(ind.len() + 1);
        //
        // for edge_op in ind.edge_ops.iter() {
        // let new_op = if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
        // match self.weighted_mut_op.ind_sample(rng) {
        // MutOp::Copy => edge_op.clone(),
        // MutOp::Insert => {
        // Insert a new op before the current operation
        // mut_ind.push(self.generate_random_edge_operation(rng));
        // edge_op.clone()
        // }
        // MutOp::Remove => {
        // remove current operation
        // continue;
        // }
        // MutOp::ModifyOp => (self.weighted_op.ind_sample(rng), edge_op.1),
        // MutOp::ModifyParam => (edge_op.0, rng.gen::<f32>()),
        // MutOp::Replace => self.generate_random_edge_operation(rng),
        // }
        // } else {
        // edge_op.clone()
        // };
        // mut_ind.push(new_op);
        // }
        //

        Genome {
            system: System::new(),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (EdgeOp, f32) {
        generate_random_edge_operation(&self.weighted_op, rng)
    }

    // There are many parameters that influence the creation of a random
    // genome:
    //
    //     - Number of rules
    //     - Arity of symbols
    //     - Axiom and Length
    //     - Length of a production rule
    //     - Number of (condition, successor) pairs per rule.
    //     - Complexity of expression in Symbol
    //
    //     - Number of Iterations.
    //
    //     There are many
    //
    pub fn random_genome<R: Rng>(&self, rng: &mut R) -> Genome {
        Genome {
            system: System::new(),
        }

    }
}

impl<N:Clone+Sync+Default,E:Clone+Sync+Default> FitnessEval<Genome, MultiObjective3<f32>> for Toolbox<N,E> {
    /// Evaluates the fitness of a Genome population.
    fn fitness(&mut self, pop: &[Genome]) -> Vec<MultiObjective3<f32>> {
        let pool = &mut self.pool;
        let goal = &self.goal;
        let axiom_args = &self.axiom_args[..];
        let iterations = self.iterations;

        let fitness_functions = self.fitness_functions;

        crossbeam::scope(|scope| {
            pool.map(scope, pop, |ind| {
                let edge_ops = ind.to_edge_ops(axiom_args, iterations);
                let g = edgeops_to_graph(&edge_ops);

                //let g = ind.to_graph();
                MultiObjective3::from((goal.apply_fitness_function(fitness_functions.0, &g),
                                       goal.apply_fitness_function(fitness_functions.1, &g),
                                       goal.apply_fitness_function(fitness_functions.2, &g)))

            })
                .collect()
        })
    }
}

impl<N: Clone + Default, E: Clone + Default> Mate<Genome> for Toolbox<N, E> {
    // p1 is potentially "better" than p2
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &Genome, p2: &Genome) -> Genome {

        match self.weighted_var_op.ind_sample(rng) {
            VarOp::Copy => p1.clone(),
            VarOp::Mutate => self.mutate(rng, p1),
            VarOp::LinearCrossover2 => {
                Genome {
                    // edge_ops: linear_2point_crossover_random(rng,
                    // &p1.edge_ops[..],
                    // &p2.edge_ops[..]),
                    system: System::new(),
                }
            }
            VarOp::UniformCrossover => {
                panic!("TODO");
            }
        }
    }
}

impl Genome {
    pub fn len(&self) -> usize {
        0 // XXX
    }

    /// Develops
    pub fn to_edge_ops(&self, _axiom_args: &[Expr<f32>], _iterations: usize) -> Vec<(EdgeOp, f32)> {
        vec![]
    }
}

#[inline]
fn generate_random_edge_operation<R: Rng>(weighted_op: &OwnedWeightedChoice<EdgeOp>,
                                          rng: &mut R)
                                          -> (EdgeOp, f32) {
    (weighted_op.ind_sample(rng), rng.gen::<f32>())
}
<commit_msg>Remove Genome#len()<commit_after>// Edge Operation L-System Genome

pub mod edgeop;
mod expr_op;
mod cond_op;

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::{self, FitnessEval, Mate, MultiObjective3};
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use rand::distributions::range::Range;
use graph_annealing::owned_weighted_choice::OwnedWeightedChoice;
use graph_annealing::fitness_function::FitnessFunction;
use graph_annealing::goal::Goal;
use std::str::FromStr;
use triadic_census::OptDenseDigraph;
use lindenmayer_system::{Alphabet, Condition, Symbol, SymbolString, System};
use lindenmayer_system::symbol::Sym2;
use lindenmayer_system::expr::Expr;
use self::edgeop::{EdgeOp, edgeops_to_graph};
use self::expr_op::{ConstExprOp, ExprOp, random_const_expr, random_expr};
use self::cond_op::{CondOp, random_cond};
use simple_parallel::Pool;
use crossbeam;

/// Element-wise Mutation operation.
defops!{MutOp;
    // No mutation (copy element)
    Copy,
    // Insert new operation
    Insert,
    // Remove an operation
    Remove,
    // Modify the operation
    ModifyOp,
    // Modify a parameter value
    ModifyParam,
    // Modify both operation and parameter
    Replace
}

/// Variation operators
defops!{VarOp;
    // No variation. Reproduce exactly
    Copy,

    // Mutate
    Mutate,

    // 2-point Linear crossover
    LinearCrossover2,

    // Uniform crossover
    UniformCrossover
}

// The alphabet of terminal and non-terminals we use.
// Non-terminals are our rules, while terminals are the EdgeOps.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum EdgeAlphabet {
    Terminal(EdgeOp),
    NonTerminal(u32),
}

impl Alphabet for EdgeAlphabet {}

// We use 2-ary symbols, i.e. symbols with two parameters.
type Sym = Sym2<EdgeAlphabet, f32>;

pub struct SymbolGenerator {
    pub max_expr_depth: usize,
    pub expr_weighted_op: OwnedWeightedChoice<ExprOp>,
    pub expr_weighted_op_max_depth: OwnedWeightedChoice<ExprOp>,

    // terminal symbols
    pub edge_weighted_op: OwnedWeightedChoice<EdgeOp>,

    pub nonterminal_symbols: Range<u32>,

    /// The probability with which a terminal value is choosen.
    pub prob_terminal: Probability,

    pub const_expr_weighted_op: OwnedWeightedChoice<ConstExprOp>,
}

impl SymbolGenerator {
    /// Generates a random production (right hand-side of a rule).
    pub fn gen_symbolstring<R, S>(&self,
                                  rng: &mut R,
                                  len: usize,
                                  arity: usize,
                                  num_params: usize)
                                  -> SymbolString<S>
        where R: Rng,
              S: Symbol<A = EdgeAlphabet, T = f32>
    {
        SymbolString((0..len)
                         .into_iter()
                         .map(|_| self.gen_symbol(rng, arity, num_params))
                         .collect())
    }

    pub fn gen_symbol<R, S>(&self, rng: &mut R, arity: usize, num_params: usize) -> S
        where R: Rng,
              S: Symbol<A = EdgeAlphabet, T = f32>
    {
        S::from_iter(self.gen_symbol_value(rng),
                     (0..arity).into_iter().map(|_| self.gen_expr(rng, num_params)))

    }

    fn gen_expr<R: Rng>(&self, rng: &mut R, num_params: usize) -> Expr<f32> {
        random_expr(rng,
                    num_params,
                    self.max_expr_depth,
                    &self.expr_weighted_op,
                    &self.expr_weighted_op_max_depth)
    }

    fn gen_terminal<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        EdgeAlphabet::Terminal(self.edge_weighted_op.ind_sample(rng))
    }

    pub fn gen_nonterminal<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        EdgeAlphabet::NonTerminal(self.nonterminal_symbols.ind_sample(rng))
    }

    fn gen_symbol_value<R: Rng>(&self, rng: &mut R) -> EdgeAlphabet {
        if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_terminal) {
            self.gen_terminal(rng)
        } else {
            self.gen_nonterminal(rng)
        }
    }

    /// Generate a simple condition like:
    ///     Arg(n) or 0.0 [>=] or [<=] constant expr
    fn gen_simple_rule_condition<R: Rng>(&self, rng: &mut R, arity: usize) -> Condition<f32> {
        let lhs = if arity > 0 {
            Expr::Arg(rng.gen_range(0, arity))
        } else {
            Expr::Const(0.0)
        };

        let rhs = random_const_expr(rng, &self.const_expr_weighted_op);

        if rng.gen::<bool>() {
            Condition::GreaterEqual(Box::new(lhs), Box::new(rhs))
        } else {
            Condition::LessEqual(Box::new(lhs), Box::new(rhs))
        }
    }

    // Generate a random rule with `symbol` and `arity` parameters.
    //
    // fn gen_rule<R: Rng>(&self, symbol: EdgeAlphabet, arity: usize) {
    // }
}

// When we need a value within (0, 1], we simply cut off the integer part.
// Max depth.

// # Genome interpretation:
//
//     * We use rule with number 0 as axiom.
//       The arguments for the axiom are fixed and passed in from the command line.
//       For simplicity, these arguments are duplicated in each Genome in `axiom_params`.
//       One could also apply genetic operations onto these.
//
//
#[derive(Clone, Debug)]
pub struct Genome {
    system: System<Sym>,
}

pub struct Toolbox<N, E> {
    goal: Goal<N, E>,
    pool: Pool,
    fitness_functions: (FitnessFunction, FitnessFunction, FitnessFunction),

    weighted_op: OwnedWeightedChoice<EdgeOp>,
    weighted_var_op: OwnedWeightedChoice<VarOp>,
    weighted_mut_op: OwnedWeightedChoice<MutOp>,
    prob_mutate_elem: Probability,

    /// Arguments to the axiom rule.
    pub axiom_args: Vec<Expr<f32>>,

    /// Maximum number of iterations of the L-system  (XXX: Limit also based on generated length)
    pub iterations: usize,
}

impl<N: Clone + Default, E: Clone + Default> Toolbox<N, E> {
    pub fn new(goal: Goal<N, E>,
               pool: Pool,
               fitness_functions: (FitnessFunction, FitnessFunction, FitnessFunction),
               weighted_op: Vec<Weighted<EdgeOp>>,
               weighted_var_op: Vec<Weighted<VarOp>>,
               weighted_mut_op: Vec<Weighted<MutOp>>,
               prob_mutate_elem: Probability)
               -> Toolbox<N, E> {

        Toolbox {
            goal: goal,
            pool: pool,
            fitness_functions: fitness_functions,
            prob_mutate_elem: prob_mutate_elem,
            weighted_op: OwnedWeightedChoice::new(weighted_op),
            weighted_var_op: OwnedWeightedChoice::new(weighted_var_op),
            weighted_mut_op: OwnedWeightedChoice::new(weighted_mut_op),
            axiom_args: vec![],
            iterations: 10,
        }
    }

    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &Genome) -> Genome {
        // let mut mut_ind = Vec::with_capacity(ind.len() + 1);
        //
        // for edge_op in ind.edge_ops.iter() {
        // let new_op = if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
        // match self.weighted_mut_op.ind_sample(rng) {
        // MutOp::Copy => edge_op.clone(),
        // MutOp::Insert => {
        // Insert a new op before the current operation
        // mut_ind.push(self.generate_random_edge_operation(rng));
        // edge_op.clone()
        // }
        // MutOp::Remove => {
        // remove current operation
        // continue;
        // }
        // MutOp::ModifyOp => (self.weighted_op.ind_sample(rng), edge_op.1),
        // MutOp::ModifyParam => (edge_op.0, rng.gen::<f32>()),
        // MutOp::Replace => self.generate_random_edge_operation(rng),
        // }
        // } else {
        // edge_op.clone()
        // };
        // mut_ind.push(new_op);
        // }
        //

        Genome {
            system: System::new(),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (EdgeOp, f32) {
        generate_random_edge_operation(&self.weighted_op, rng)
    }

    // There are many parameters that influence the creation of a random
    // genome:
    //
    //     - Number of rules
    //     - Arity of symbols
    //     - Axiom and Length
    //     - Length of a production rule
    //     - Number of (condition, successor) pairs per rule.
    //     - Complexity of expression in Symbol
    //
    //     - Number of Iterations.
    //
    //     There are many
    //
    pub fn random_genome<R: Rng>(&self, rng: &mut R) -> Genome {
        Genome {
            system: System::new(),
        }

    }
}

impl<N:Clone+Sync+Default,E:Clone+Sync+Default> FitnessEval<Genome, MultiObjective3<f32>> for Toolbox<N,E> {
    /// Evaluates the fitness of a Genome population.
    fn fitness(&mut self, pop: &[Genome]) -> Vec<MultiObjective3<f32>> {
        let pool = &mut self.pool;
        let goal = &self.goal;
        let axiom_args = &self.axiom_args[..];
        let iterations = self.iterations;

        let fitness_functions = self.fitness_functions;

        crossbeam::scope(|scope| {
            pool.map(scope, pop, |ind| {
                let edge_ops = ind.to_edge_ops(axiom_args, iterations);
                let g = edgeops_to_graph(&edge_ops);

                //let g = ind.to_graph();
                MultiObjective3::from((goal.apply_fitness_function(fitness_functions.0, &g),
                                       goal.apply_fitness_function(fitness_functions.1, &g),
                                       goal.apply_fitness_function(fitness_functions.2, &g)))

            })
                .collect()
        })
    }
}

impl<N: Clone + Default, E: Clone + Default> Mate<Genome> for Toolbox<N, E> {
    // p1 is potentially "better" than p2
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &Genome, p2: &Genome) -> Genome {

        match self.weighted_var_op.ind_sample(rng) {
            VarOp::Copy => p1.clone(),
            VarOp::Mutate => self.mutate(rng, p1),
            VarOp::LinearCrossover2 => {
                Genome {
                    // edge_ops: linear_2point_crossover_random(rng,
                    // &p1.edge_ops[..],
                    // &p2.edge_ops[..]),
                    system: System::new(),
                }
            }
            VarOp::UniformCrossover => {
                panic!("TODO");
            }
        }
    }
}

impl Genome {
    /// Develops
    pub fn to_edge_ops(&self, _axiom_args: &[Expr<f32>], _iterations: usize) -> Vec<(EdgeOp, f32)> {
        vec![]
    }
}

#[inline]
fn generate_random_edge_operation<R: Rng>(weighted_op: &OwnedWeightedChoice<EdgeOp>,
                                          rng: &mut R)
                                          -> (EdgeOp, f32) {
    (weighted_op.ind_sample(rng), rng.gen::<f32>())
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! How to retreive data from an image within a shader.
//!
//! This module contains a struct named `Sampler` which describes how to get pixel data from
//! a texture.
//!
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Describes how to retreive data from an image within a shader.
pub struct Sampler {
    sampler: vk::Sampler,
    device: Arc<Device>,
}

// TODO: what's the story with VK_KHR_mirror_clamp_to_edge? Is it an extension or is it core?

impl Sampler {
    /// Creates a new `Sampler` with the given behavior.
    ///
    /// # Panic
    ///
    /// - Panicks if `max_anisotropy < 1.0`.
    /// - Panicks if `min_lod > max_lod`.
    ///
    // TODO: wrong error type returned
    pub fn new(device: &Arc<Device>, mag_filter: Filter, min_filter: Filter,
               mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
               address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
               max_anisotropy: f32, min_lod: f32, max_lod: f32)
               -> Result<Arc<Sampler>, SamplerCreationError>
    {
        assert!(max_anisotropy >= 1.0);
        assert!(min_lod <= max_lod);

        if max_anisotropy > 1.0 {
            if !device.enabled_features().sampler_anisotropy {
                return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
            }

            let limit = device.physical_device().limits().max_sampler_anisotropy();
            if max_anisotropy > limit {
                return Err(SamplerCreationError::AnisotropyLimitExceeded {
                    requested: max_anisotropy,
                    maximum: limit,
                });
            }
        }

        {
            let limit = device.physical_device().limits().max_sampler_lod_bias();
            if mip_lod_bias > limit {
                return Err(SamplerCreationError::MipLodBiasLimitExceeded {
                    requested: mip_lod_bias,
                    maximum: limit,
                });
            }
        }

        let vk = device.pointers();

        let sampler = unsafe {
            let infos = vk::SamplerCreateInfo {
                sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                magFilter: mag_filter as u32,
                minFilter: min_filter as u32,
                mipmapMode: mipmap_mode as u32,
                addressModeU: address_u as u32,
                addressModeV: address_v as u32,
                addressModeW: address_w as u32,
                mipLodBias: mip_lod_bias,
                anisotropyEnable: if max_anisotropy > 1.0 { vk::TRUE } else { vk::FALSE },
                maxAnisotropy: max_anisotropy,
                compareEnable: 0,       // FIXME:
                compareOp: 0,       // FIXME:
                minLod: min_lod,
                maxLod: max_lod,
                borderColor: 0,     // FIXME:
                unnormalizedCoordinates: vk::FALSE,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSampler(device.internal_object(), &infos,
                                               ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Sampler {
            sampler: sampler,
            device: device.clone(),
        }))
    }

    /// Creates a sampler with unnormalized coordinates. This means that texture coordinates won't
    /// range between `0.0` and `1.0` but use plain pixel offsets.
    ///
    /// Using an unnormalized sampler adds a few restrictions:
    ///
    /// - It can only be used with non-array 1D or 2D images.
    /// - It can only be used with images with a single mipmap.
    /// - Projection and offsets can't be used by shaders. Only the first mipmap can be accessed.
    ///
    // TODO: wrong error type returned
    pub fn unnormalized(device: &Arc<Device>, filter: Filter,
                        address_u: UnnormalizedSamplerAddressMode,
                        address_v: UnnormalizedSamplerAddressMode)
                        -> Result<Arc<Sampler>, SamplerCreationError>
    {
        let vk = device.pointers();

        let sampler = unsafe {
            let infos = vk::SamplerCreateInfo {
                sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                magFilter: filter as u32,
                minFilter: filter as u32,
                mipmapMode: vk::SAMPLER_MIPMAP_MODE_NEAREST,
                addressModeU: address_u as u32,
                addressModeV: address_v as u32,
                addressModeW: vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,       // unused by the impl
                mipLodBias: 0.0,
                anisotropyEnable: vk::FALSE,
                maxAnisotropy: 0.0,
                compareEnable: vk::FALSE,
                compareOp: vk::COMPARE_OP_NEVER,
                minLod: 0.0,
                maxLod: 0.0,
                borderColor: 0,     // FIXME:
                unnormalizedCoordinates: vk::TRUE,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSampler(device.internal_object(), &infos,
                                               ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Sampler {
            sampler: sampler,
            device: device.clone(),
        }))
    }
}

unsafe impl VulkanObject for Sampler {
    type Object = vk::Sampler;

    #[inline]
    fn internal_object(&self) -> vk::Sampler {
        self.sampler
    }
}

impl Drop for Sampler {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySampler(self.device.internal_object(), self.sampler, ptr::null());
        }
    }
}

/// Describes how the color of each pixel should be determined.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum Filter {
    /// The four pixels whose center surround the requested coordinates are taken, then their
    /// values are interpolated.
    Linear = vk::FILTER_LINEAR,

    /// The pixel whose center is nearest to the requested coordinates is taken from the source
    /// and its value is returned as-is.
    Nearest = vk::FILTER_NEAREST,
}

/// Describes which mipmap from the source to use.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum MipmapMode {
    /// Use the mipmap whose dimensions are the nearest to the dimensions of the destination.
    Nearest = vk::SAMPLER_MIPMAP_MODE_NEAREST,

    /// Take the two mipmaps whose dimensions are immediately inferior and superior to the
    /// dimensions of the destination, calculate the value for both, and interpolate them.
    Linear = vk::SAMPLER_MIPMAP_MODE_LINEAR,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum SamplerAddressMode {
    Repeat = vk::SAMPLER_ADDRESS_MODE_REPEAT,
    MirroredRepeat = vk::SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
    ClampToEdge = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
    ClampToBorder = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
    MirrorClampToEdge = vk::SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum UnnormalizedSamplerAddressMode {
    ClampToEdge = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
    ClampToBorder = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
}

/// Error that can happen when creating an instance.
#[derive(Clone, Debug, PartialEq)]
pub enum SamplerCreationError {
    /// Not enough memory.
    OomError(OomError),

    /// Too many sampler objects have been created. You must destroy some before creating new ones.
    /// Note the specs guarantee that at least 4000 samplers can exist simultaneously.
    TooManyObjects,

    /// Using an anisotropy superior to 1.0 requires enabling the `sampler_anisotropy` feature when
    /// creating the device.
    SamplerAnisotropyFeatureNotEnabled,

    /// The requested anisotropy level exceeds the device's limits.
    AnisotropyLimitExceeded { requested: f32, maximum: f32 },

    /// The requested mip lod bias exceeds the device's limits.
    MipLodBiasLimitExceeded { requested: f32, maximum: f32 },
}

impl error::Error for SamplerCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            SamplerCreationError::OomError(_) => "not enough memory available",
            SamplerCreationError::TooManyObjects => "too many simultaneous sampler objects",
            SamplerCreationError::SamplerAnisotropyFeatureNotEnabled => "the `sampler_anisotropy` \
                                                                         feature is not enabled",
            SamplerCreationError::AnisotropyLimitExceeded { .. } => "anisotropy limit exceeded",
            SamplerCreationError::MipLodBiasLimitExceeded { .. } => "mip lod bias limit exceeded",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SamplerCreationError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for SamplerCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for SamplerCreationError {
    #[inline]
    fn from(err: OomError) -> SamplerCreationError {
        SamplerCreationError::OomError(err)
    }
}

impl From<Error> for SamplerCreationError {
    #[inline]
    fn from(err: Error) -> SamplerCreationError {
        match err {
            err @ Error::OutOfHostMemory => SamplerCreationError::OomError(OomError::from(err)),
            err @ Error::OutOfDeviceMemory => SamplerCreationError::OomError(OomError::from(err)),
            Error::TooManyObjects => SamplerCreationError::TooManyObjects,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

#[cfg(test)]
mod tests {
    use sampler;

    #[test]
    fn create_regular() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 1.0,
                                      0.0, 2.0).unwrap();
    }

    #[test]
    fn create_unnormalized() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::unnormalized(&device, sampler::Filter::Linear,
                                               sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
                                               sampler::UnnormalizedSamplerAddressMode::ClampToEdge)
                                               .unwrap();
    }

    #[test]
    #[should_panic]
    fn min_lod_inferior() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 1.0, 5.0, 2.0);
    }

    #[test]
    #[should_panic]
    fn max_anisotropy() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 0.5, 0.0, 2.0);
    }

    #[test]
    fn anisotropy_feature() {
        let (device, queue) = gfx_dev_and_queue!();

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 2.0, 0.0, 2.0);

        match r {
            Err(sampler::SamplerCreationError::SamplerAnisotropyFeatureNotEnabled) => (),
            _ => panic!()
        }
    }

    #[test]
    fn anisotropy_limit() {
        let (device, queue) = gfx_dev_and_queue!(sampler_anisotropy);

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 100000000.0, 0.0,
                                      2.0);

        match r {
            Err(sampler::SamplerCreationError::AnisotropyLimitExceeded { .. }) => (),
            _ => panic!()
        }
    }

    #[test]
    fn mip_lod_bias_limit() {
        let (device, queue) = gfx_dev_and_queue!();

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 100000000.0, 1.0, 0.0,
                                      2.0);

        match r {
            Err(sampler::SamplerCreationError::MipLodBiasLimitExceeded { .. }) => (),
            _ => panic!()
        }
    }
}
<commit_msg>Remove TODO<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! How to retreive data from an image within a shader.
//!
//! This module contains a struct named `Sampler` which describes how to get pixel data from
//! a texture.
//!
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use device::Device;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Describes how to retreive data from an image within a shader.
pub struct Sampler {
    sampler: vk::Sampler,
    device: Arc<Device>,
}

// TODO: what's the story with VK_KHR_mirror_clamp_to_edge? Is it an extension or is it core?

impl Sampler {
    /// Creates a new `Sampler` with the given behavior.
    ///
    /// # Panic
    ///
    /// - Panicks if `max_anisotropy < 1.0`.
    /// - Panicks if `min_lod > max_lod`.
    ///
    pub fn new(device: &Arc<Device>, mag_filter: Filter, min_filter: Filter,
               mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
               address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
               max_anisotropy: f32, min_lod: f32, max_lod: f32)
               -> Result<Arc<Sampler>, SamplerCreationError>
    {
        assert!(max_anisotropy >= 1.0);
        assert!(min_lod <= max_lod);

        if max_anisotropy > 1.0 {
            if !device.enabled_features().sampler_anisotropy {
                return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
            }

            let limit = device.physical_device().limits().max_sampler_anisotropy();
            if max_anisotropy > limit {
                return Err(SamplerCreationError::AnisotropyLimitExceeded {
                    requested: max_anisotropy,
                    maximum: limit,
                });
            }
        }

        {
            let limit = device.physical_device().limits().max_sampler_lod_bias();
            if mip_lod_bias > limit {
                return Err(SamplerCreationError::MipLodBiasLimitExceeded {
                    requested: mip_lod_bias,
                    maximum: limit,
                });
            }
        }

        let vk = device.pointers();

        let sampler = unsafe {
            let infos = vk::SamplerCreateInfo {
                sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                magFilter: mag_filter as u32,
                minFilter: min_filter as u32,
                mipmapMode: mipmap_mode as u32,
                addressModeU: address_u as u32,
                addressModeV: address_v as u32,
                addressModeW: address_w as u32,
                mipLodBias: mip_lod_bias,
                anisotropyEnable: if max_anisotropy > 1.0 { vk::TRUE } else { vk::FALSE },
                maxAnisotropy: max_anisotropy,
                compareEnable: 0,       // FIXME:
                compareOp: 0,       // FIXME:
                minLod: min_lod,
                maxLod: max_lod,
                borderColor: 0,     // FIXME:
                unnormalizedCoordinates: vk::FALSE,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSampler(device.internal_object(), &infos,
                                               ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Sampler {
            sampler: sampler,
            device: device.clone(),
        }))
    }

    /// Creates a sampler with unnormalized coordinates. This means that texture coordinates won't
    /// range between `0.0` and `1.0` but use plain pixel offsets.
    ///
    /// Using an unnormalized sampler adds a few restrictions:
    ///
    /// - It can only be used with non-array 1D or 2D images.
    /// - It can only be used with images with a single mipmap.
    /// - Projection and offsets can't be used by shaders. Only the first mipmap can be accessed.
    ///
    pub fn unnormalized(device: &Arc<Device>, filter: Filter,
                        address_u: UnnormalizedSamplerAddressMode,
                        address_v: UnnormalizedSamplerAddressMode)
                        -> Result<Arc<Sampler>, SamplerCreationError>
    {
        let vk = device.pointers();

        let sampler = unsafe {
            let infos = vk::SamplerCreateInfo {
                sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                magFilter: filter as u32,
                minFilter: filter as u32,
                mipmapMode: vk::SAMPLER_MIPMAP_MODE_NEAREST,
                addressModeU: address_u as u32,
                addressModeV: address_v as u32,
                addressModeW: vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,       // unused by the impl
                mipLodBias: 0.0,
                anisotropyEnable: vk::FALSE,
                maxAnisotropy: 0.0,
                compareEnable: vk::FALSE,
                compareOp: vk::COMPARE_OP_NEVER,
                minLod: 0.0,
                maxLod: 0.0,
                borderColor: 0,     // FIXME:
                unnormalizedCoordinates: vk::TRUE,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSampler(device.internal_object(), &infos,
                                               ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Sampler {
            sampler: sampler,
            device: device.clone(),
        }))
    }
}

unsafe impl VulkanObject for Sampler {
    type Object = vk::Sampler;

    #[inline]
    fn internal_object(&self) -> vk::Sampler {
        self.sampler
    }
}

impl Drop for Sampler {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySampler(self.device.internal_object(), self.sampler, ptr::null());
        }
    }
}

/// Describes how the color of each pixel should be determined.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum Filter {
    /// The four pixels whose center surround the requested coordinates are taken, then their
    /// values are interpolated.
    Linear = vk::FILTER_LINEAR,

    /// The pixel whose center is nearest to the requested coordinates is taken from the source
    /// and its value is returned as-is.
    Nearest = vk::FILTER_NEAREST,
}

/// Describes which mipmap from the source to use.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum MipmapMode {
    /// Use the mipmap whose dimensions are the nearest to the dimensions of the destination.
    Nearest = vk::SAMPLER_MIPMAP_MODE_NEAREST,

    /// Take the two mipmaps whose dimensions are immediately inferior and superior to the
    /// dimensions of the destination, calculate the value for both, and interpolate them.
    Linear = vk::SAMPLER_MIPMAP_MODE_LINEAR,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum SamplerAddressMode {
    Repeat = vk::SAMPLER_ADDRESS_MODE_REPEAT,
    MirroredRepeat = vk::SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
    ClampToEdge = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
    ClampToBorder = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
    MirrorClampToEdge = vk::SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum UnnormalizedSamplerAddressMode {
    ClampToEdge = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
    ClampToBorder = vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
}

/// Error that can happen when creating an instance.
#[derive(Clone, Debug, PartialEq)]
pub enum SamplerCreationError {
    /// Not enough memory.
    OomError(OomError),

    /// Too many sampler objects have been created. You must destroy some before creating new ones.
    /// Note the specs guarantee that at least 4000 samplers can exist simultaneously.
    TooManyObjects,

    /// Using an anisotropy superior to 1.0 requires enabling the `sampler_anisotropy` feature when
    /// creating the device.
    SamplerAnisotropyFeatureNotEnabled,

    /// The requested anisotropy level exceeds the device's limits.
    AnisotropyLimitExceeded { requested: f32, maximum: f32 },

    /// The requested mip lod bias exceeds the device's limits.
    MipLodBiasLimitExceeded { requested: f32, maximum: f32 },
}

impl error::Error for SamplerCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            SamplerCreationError::OomError(_) => "not enough memory available",
            SamplerCreationError::TooManyObjects => "too many simultaneous sampler objects",
            SamplerCreationError::SamplerAnisotropyFeatureNotEnabled => "the `sampler_anisotropy` \
                                                                         feature is not enabled",
            SamplerCreationError::AnisotropyLimitExceeded { .. } => "anisotropy limit exceeded",
            SamplerCreationError::MipLodBiasLimitExceeded { .. } => "mip lod bias limit exceeded",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SamplerCreationError::OomError(ref err) => Some(err),
            _ => None
        }
    }
}

impl fmt::Display for SamplerCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for SamplerCreationError {
    #[inline]
    fn from(err: OomError) -> SamplerCreationError {
        SamplerCreationError::OomError(err)
    }
}

impl From<Error> for SamplerCreationError {
    #[inline]
    fn from(err: Error) -> SamplerCreationError {
        match err {
            err @ Error::OutOfHostMemory => SamplerCreationError::OomError(OomError::from(err)),
            err @ Error::OutOfDeviceMemory => SamplerCreationError::OomError(OomError::from(err)),
            Error::TooManyObjects => SamplerCreationError::TooManyObjects,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

#[cfg(test)]
mod tests {
    use sampler;

    #[test]
    fn create_regular() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 1.0,
                                      0.0, 2.0).unwrap();
    }

    #[test]
    fn create_unnormalized() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::unnormalized(&device, sampler::Filter::Linear,
                                               sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
                                               sampler::UnnormalizedSamplerAddressMode::ClampToEdge)
                                               .unwrap();
    }

    #[test]
    #[should_panic]
    fn min_lod_inferior() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 1.0, 5.0, 2.0);
    }

    #[test]
    #[should_panic]
    fn max_anisotropy() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 0.5, 0.0, 2.0);
    }

    #[test]
    fn anisotropy_feature() {
        let (device, queue) = gfx_dev_and_queue!();

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 2.0, 0.0, 2.0);

        match r {
            Err(sampler::SamplerCreationError::SamplerAnisotropyFeatureNotEnabled) => (),
            _ => panic!()
        }
    }

    #[test]
    fn anisotropy_limit() {
        let (device, queue) = gfx_dev_and_queue!(sampler_anisotropy);

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 1.0, 100000000.0, 0.0,
                                      2.0);

        match r {
            Err(sampler::SamplerCreationError::AnisotropyLimitExceeded { .. }) => (),
            _ => panic!()
        }
    }

    #[test]
    fn mip_lod_bias_limit() {
        let (device, queue) = gfx_dev_and_queue!();

        let r = sampler::Sampler::new(&device, sampler::Filter::Linear, sampler::Filter::Linear,
                                      sampler::MipmapMode::Nearest,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat,
                                      sampler::SamplerAddressMode::Repeat, 100000000.0, 1.0, 0.0,
                                      2.0);

        match r {
            Err(sampler::SamplerCreationError::MipLodBiasLimitExceeded { .. }) => (),
            _ => panic!()
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Write,Result};
use std::path::Path;

use build_scalar_array::{types, angle_types, dims};

fn declare_vec(f: &mut File) -> Result<()> {
    let un_ops = ["Neg", "Not"];
    let bin_ops = ["BitAnd", "BitOr", "BitXor", "Add", "Div", "Mul", "Rem", "Sub", "Shl", "Shr"];

    try!(write!(f,"use std::ops::{{"));
    for trait_name in un_ops.iter().chain(bin_ops.iter()) {
        try!(write!(f,"{},", trait_name));
    }
    try!(write!(f,"}};\n\n"));

    try!(write!(f,"use angle::{{"));
    for t in angle_types().iter() {
        try!(write!(f,"{},",t));
    }
    try!(write!(f,"}};\n"));

    try!(write!(f,"use scalar_array::{{"));
    for d in dims().iter() {
        try!(write!(f,"{},", d));
    }
    try!(write!(f,"}};\n\n"));

    for trait_name in un_ops.iter() {
        try!(impl_unop(f, trait_name));
    }

    for trait_name in bin_ops.iter() {
        try!(impl_binop(f, trait_name));
    }
    try!(impl_from(f));

    for (i, d) in dims().iter().enumerate() {
        let i = i+1;
        try!(write!(f,"
/// An alias for Vec<{d}, T>
pub type Vec{i}<T> = Vec<{d}, T>;

impl <T: Scalar> From<[T; {i}]> for Vec{i}<T> {{  fn from(v: [T; {i}]) -> Self {{ Vec(v) }}  }}
impl <T: Scalar> Into<[T; {i}]> for Vec{i}<T> {{  fn into(self) -> [T; {i}] {{ self.0 }}  }}

impl <T: Scalar> Borrow   <[T; {i}]> for Vec{i}<T> {{  #[inline] fn borrow    (&    self) -> &    [T; {i}] {{ &    self.0 }}  }}
impl <T: Scalar> BorrowMut<[T; {i}]> for Vec{i}<T> {{  #[inline] fn borrow_mut(&mut self) -> &mut [T; {i}] {{ &mut self.0 }}  }}

impl <T: Scalar> AsRef<[T; {i}]> for Vec{i}<T> {{  #[inline] fn as_ref(&    self) -> &    [T; {i}] {{ &    self.0 }}  }}
impl <T: Scalar> AsMut<[T; {i}]> for Vec{i}<T> {{  #[inline] fn as_mut(&mut self) -> &mut [T; {i}] {{ &mut self.0 }}  }}\n", i=i, d=d));
    }

    // TODO: re-enable when it stop breaking rust
    /*for scalar_type in types().iter() {
        for trait_name in bin_ops.iter() {
            try!(write!(f, "
impl <T: Scalar, D: Dim<T>> {trait_name}<Vec<D, T>> for {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(self, *r))))
    }}
}}
impl <'t, T: Scalar, D: Dim<T>> {trait_name}<Vec<D, T>> for &'t {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(*self, *r))))
    }}
}}
impl <'u, T: Scalar, D: Dim<T>> {trait_name}<&'u Vec<D, T>> for {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(self, *r))))
    }}
}}
impl <'t, 'u, T: Scalar, D: Dim<T>> {trait_name}<&'u Vec<D, T>> for &'t {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(*self, *r))))
    }}
}}", trait_name=trait_name, method_name=trait_name.to_lowercase(), scalar_type=scalar_type));
        }
    }*/

    write!(f, "\n")
}

fn impl_unop(f: &mut File, trait_name: &str) -> Result<()> {
    write!(f, "
impl <T: Scalar, D: Dim<T>> {trait_name} for Vec<D, T>
where T: {trait_name},
<T as {trait_name}>::Output: Scalar,
D: Dim<<T as {trait_name}>::Output> {{
    type Output = Vec<D, <T as {trait_name}>::Output>;
    fn {method_name}(self) -> Self::Output {{ {trait_name}::{method_name}(&self) }}
}}
impl <'t, T: Scalar, D: Dim<T>> {trait_name} for &'t Vec<D, T>
where T: {trait_name},
<T as {trait_name}>::Output: Scalar,
D: Dim<<T as {trait_name}>::Output> {{
    type Output = Vec<D, <T as {trait_name}>::Output>;
    fn {method_name}(self) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}>::Output>>::from_iter(self.iter().map(|v| {trait_name}::{method_name}(*v))))
    }}
}}\n", trait_name=trait_name, method_name=trait_name.to_lowercase())
}

fn impl_binop(f: &mut File, trait_name: &str) -> Result<()> {
    write!(f, "
impl <T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<Vec<D, U>> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(&self, &rhs) }}
}}
impl <'t, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<Vec<D, U>> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(self, &rhs) }}
}}
impl <'u, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<&'u Vec<D, U>> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(&self, rhs) }}
}}
impl <'t, 'u, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<&'u Vec<D, U>> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, U>) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}<U>>::Output>>::from_iter(self.iter().zip(rhs.iter()).map(|(l, r)| {trait_name}::{method_name}(*l, *r))))
    }}
}}

impl <T: Scalar, U: Scalar, D: Dim<T>> {trait_name}<U> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: U) -> Self::Output {{ {trait_name}::{method_name}(&self, rhs) }}
}}
impl <'t, T: Scalar, U: Scalar, D: Dim<T>> {trait_name}<U> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: U) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}<U>>::Output>>::from_iter(self.iter().map(|l| {trait_name}::{method_name}(*l, rhs))))
    }}
}}\n", trait_name=trait_name, method_name=trait_name.to_lowercase())
}

fn impl_from(f: &mut File) -> Result<()> {
    for t in types().iter().filter(|&t| *t != "bool") {
        for u in types().iter().filter(|&t| *t != "bool") {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v as {t}))) }}  }}\n", t=t, u=u));
        }
        for u in angle_types().iter() {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v.into()))) }}  }}\n", t=t, u=u));
        }
    }
    for t in angle_types().iter() {
        for u in types().iter().chain(angle_types().iter()).filter(|t| **t != "bool") {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v.into()))) }}  }}\n", t=t, u=u));
        }
    }
    write!(f, "\n")
}

pub fn main(out_dir: &String) {
    let dest_path = Path::new(out_dir).join("vec.rs");
    let mut f = File::create(&dest_path).unwrap();
    declare_vec(&mut f).unwrap();
}
<commit_msg>Added From and Into for Vec/Tuple<commit_after>use std::fs::File;
use std::io::{Write,Result};
use std::path::Path;

use build_scalar_array::{types, angle_types, dims};

fn declare_vec(f: &mut File) -> Result<()> {
    let un_ops = ["Neg", "Not"];
    let bin_ops = ["BitAnd", "BitOr", "BitXor", "Add", "Div", "Mul", "Rem", "Sub", "Shl", "Shr"];

    try!(write!(f,"use std::ops::{{"));
    for trait_name in un_ops.iter().chain(bin_ops.iter()) {
        try!(write!(f,"{},", trait_name));
    }
    try!(write!(f,"}};\n\n"));

    try!(write!(f,"use angle::{{"));
    for t in angle_types().iter() {
        try!(write!(f,"{},",t));
    }
    try!(write!(f,"}};\n"));

    try!(write!(f,"use scalar_array::{{"));
    for d in dims().iter() {
        try!(write!(f,"{},", d));
    }
    try!(write!(f,"}};\n\n"));

    for trait_name in un_ops.iter() {
        try!(impl_unop(f, trait_name));
    }

    for trait_name in bin_ops.iter() {
        try!(impl_binop(f, trait_name));
    }
    try!(impl_from(f));

    for (i, d) in dims().iter().enumerate() {
        let i = i+1;
        let tuple = (0..i).fold(String::with_capacity(i*2), |acc, _| acc+"T,");
        let tpat = (0..i).fold(String::with_capacity(i*3), |acc, i| acc+"v"+i.to_string().as_ref()+",");
        let selfpat = (0..i).fold(String::with_capacity(i*8), |acc, i| acc+"self["+i.to_string().as_ref()+"],");
        try!(write!(f,"
/// An alias for Vec<{d}, T>
pub type Vec{i}<T> = Vec<{d}, T>;

impl <T: Scalar> From<[T; {i}]> for Vec{i}<T> {{  fn from(v: [T; {i}]) -> Self {{ Vec(v) }}  }}
impl <T: Scalar> Into<[T; {i}]> for Vec{i}<T> {{  fn into(self) -> [T; {i}] {{ self.0 }}  }}

impl <T: Scalar> From<({tuple})> for Vec{i}<T> {{  fn from(({tpat}): ({tuple})) -> Self {{ Vec([{tpat}]) }}  }}
impl <T: Scalar> Into<({tuple})> for Vec{i}<T> {{  fn into(self) -> ({tuple}) {{ ({selfpat}) }}  }}

impl <T: Scalar> Borrow   <[T; {i}]> for Vec{i}<T> {{  #[inline] fn borrow    (&    self) -> &    [T; {i}] {{ &    self.0 }}  }}
impl <T: Scalar> BorrowMut<[T; {i}]> for Vec{i}<T> {{  #[inline] fn borrow_mut(&mut self) -> &mut [T; {i}] {{ &mut self.0 }}  }}

impl <T: Scalar> AsRef<[T; {i}]> for Vec{i}<T> {{  #[inline] fn as_ref(&    self) -> &    [T; {i}] {{ &    self.0 }}  }}
impl <T: Scalar> AsMut<[T; {i}]> for Vec{i}<T> {{  #[inline] fn as_mut(&mut self) -> &mut [T; {i}] {{ &mut self.0 }}  }}\n", i=i, d=d, tuple=tuple, tpat=tpat, selfpat=selfpat));
    }

    // TODO: re-enable when it stop breaking rust
    /*for scalar_type in types().iter() {
        for trait_name in bin_ops.iter() {
            try!(write!(f, "
impl <T: Scalar, D: Dim<T>> {trait_name}<Vec<D, T>> for {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(self, *r))))
    }}
}}
impl <'t, T: Scalar, D: Dim<T>> {trait_name}<Vec<D, T>> for &'t {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(*self, *r))))
    }}
}}
impl <'u, T: Scalar, D: Dim<T>> {trait_name}<&'u Vec<D, T>> for {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(self, *r))))
    }}
}}
impl <'t, 'u, T: Scalar, D: Dim<T>> {trait_name}<&'u Vec<D, T>> for &'t {scalar_type}
where {scalar_type}: {trait_name}<T>,
<{scalar_type} as {trait_name}<T>>::Output: Scalar,
D: Dim<<{scalar_type} as {trait_name}<T>>::Output> {{
    type Output = Vec<D, <{scalar_type} as {trait_name}<T>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, T>) -> Self::Output {{
        Vec(<D as Dim<<{scalar_type} as {trait_name}<T>>::Output>>::from_iter(rhs.iter().map(|r| {trait_name}::<T>::{method_name}(*self, *r))))
    }}
}}", trait_name=trait_name, method_name=trait_name.to_lowercase(), scalar_type=scalar_type));
        }
    }*/

    write!(f, "\n")
}

fn impl_unop(f: &mut File, trait_name: &str) -> Result<()> {
    write!(f, "
impl <T: Scalar, D: Dim<T>> {trait_name} for Vec<D, T>
where T: {trait_name},
<T as {trait_name}>::Output: Scalar,
D: Dim<<T as {trait_name}>::Output> {{
    type Output = Vec<D, <T as {trait_name}>::Output>;
    fn {method_name}(self) -> Self::Output {{ {trait_name}::{method_name}(&self) }}
}}
impl <'t, T: Scalar, D: Dim<T>> {trait_name} for &'t Vec<D, T>
where T: {trait_name},
<T as {trait_name}>::Output: Scalar,
D: Dim<<T as {trait_name}>::Output> {{
    type Output = Vec<D, <T as {trait_name}>::Output>;
    fn {method_name}(self) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}>::Output>>::from_iter(self.iter().map(|v| {trait_name}::{method_name}(*v))))
    }}
}}\n", trait_name=trait_name, method_name=trait_name.to_lowercase())
}

fn impl_binop(f: &mut File, trait_name: &str) -> Result<()> {
    write!(f, "
impl <T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<Vec<D, U>> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(&self, &rhs) }}
}}
impl <'t, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<Vec<D, U>> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(self, &rhs) }}
}}
impl <'u, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<&'u Vec<D, U>> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, U>) -> Self::Output {{ {trait_name}::{method_name}(&self, rhs) }}
}}
impl <'t, 'u, T: Scalar, U: Scalar, D: Dim<T> + Dim<U>> {trait_name}<&'u Vec<D, U>> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: &'u Vec<D, U>) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}<U>>::Output>>::from_iter(self.iter().zip(rhs.iter()).map(|(l, r)| {trait_name}::{method_name}(*l, *r))))
    }}
}}

impl <T: Scalar, U: Scalar, D: Dim<T>> {trait_name}<U> for Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: U) -> Self::Output {{ {trait_name}::{method_name}(&self, rhs) }}
}}
impl <'t, T: Scalar, U: Scalar, D: Dim<T>> {trait_name}<U> for &'t Vec<D, T>
where T: {trait_name}<U>,
<T as {trait_name}<U>>::Output: Scalar,
D: Dim<<T as {trait_name}<U>>::Output> {{
    type Output = Vec<D, <T as {trait_name}<U>>::Output>;
    fn {method_name}(self, rhs: U) -> Self::Output {{
        Vec(<D as Dim<<T as {trait_name}<U>>::Output>>::from_iter(self.iter().map(|l| {trait_name}::{method_name}(*l, rhs))))
    }}
}}\n", trait_name=trait_name, method_name=trait_name.to_lowercase())
}

fn impl_from(f: &mut File) -> Result<()> {
    for t in types().iter().filter(|&t| *t != "bool") {
        for u in types().iter().filter(|&t| *t != "bool") {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v as {t}))) }}  }}\n", t=t, u=u));
        }
        for u in angle_types().iter() {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v.into()))) }}  }}\n", t=t, u=u));
        }
    }
    for t in angle_types().iter() {
        for u in types().iter().chain(angle_types().iter()).filter(|t| **t != "bool") {
            if t == u { continue; }
            try!(write!(f,"impl <D: Dim<{t:5}>+Dim<{u:5}>> From<Vec<D, {u:5}>> for Vec<D, {t:5}> {{  fn from(v: Vec<D, {u:5}>) -> Self {{ Vec(<D as Dim<{t:5}>>::from_iter(v.iter().map(|&v| v.into()))) }}  }}\n", t=t, u=u));
        }
    }
    write!(f, "\n")
}

pub fn main(out_dir: &String) {
    let dest_path = Path::new(out_dir).join("vec.rs");
    let mut f = File::create(&dest_path).unwrap();
    declare_vec(&mut f).unwrap();
}
<|endoftext|>


<commit_before><commit_msg>have to use a non-mut vmctx for now<commit_after><|endoftext|>


<commit_before>//! Procedural macro implementing `#[derive(EnumMap)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    for &Variant {
             ref data,
             ref discriminant,
             ..
         } in variants {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            panic!("#[derive(EnumMap)] doesn't currently support discriminants");
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(name).take(variants.len());
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..variants.len();

    let to_usize = if variants.len() == 0 {
        quote! { unreachable!() }
    } else {
        quote! { self as usize }
    };

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                #to_usize
            }
            fn from_function<F: FnMut(Self) -> V>(mut f: F) -> Self::Array {
                [#(
                    f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
            Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
            _ => panic!("#[derive(EnumMap)] is only defined for enums"),
        }
        .parse()
        .unwrap()
}
<commit_msg>Correct formatting of generate_enum_code iteration<commit_after>//! Procedural macro implementing `#[derive(EnumMap)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    for &Variant {
            ref data,
            ref discriminant,
            ..
        } in variants {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            panic!("#[derive(EnumMap)] doesn't currently support discriminants");
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(name).take(variants.len());
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..variants.len();

    let to_usize = if variants.len() == 0 {
        quote! { unreachable!() }
    } else {
        quote! { self as usize }
    };

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                #to_usize
            }
            fn from_function<F: FnMut(Self) -> V>(mut f: F) -> Self::Array {
                [#(
                    f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
            Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
            _ => panic!("#[derive(EnumMap)] is only defined for enums"),
        }
        .parse()
        .unwrap()
}
<|endoftext|>


<commit_before>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {

    /// Obtain a unique name of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 192**:: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

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

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" => Some(Default),
            "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Data type representing the default character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {

    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the UTF-8 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy)]
pub struct Utf8CharacterSetCodec;

impl TextCodec for Utf8CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 192"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        UTF_8
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        UTF_8
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the GB18030 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy)]
pub struct Gb18030CharacterSetCodec;

impl TextCodec for Gb18030CharacterSetCodec {
    fn name(&self) -> &'static str {
        "GB18030"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        GB18030
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        GB18030
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}
<commit_msg>[encoding] ISO-IR 100 + ISO-IR 101<commit_after>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, ISO_8859_2, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {
    /// Obtain the defined term (unique name) of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 101** (ISO-8859-1): Right-hand part of the latin alphabet no. 1,
    /// the Western Europe character set.
    IsoIr100,
    /// **ISO-IR 101** (ISO-8859-2): Right-hand part of the latin alphabet no. 2,
    /// the Eastern Europe character set.
    IsoIr101,
    /// **ISO-IR 192**:: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

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

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" | "ISO_IR 6" => Some(Default),
            "ISO_IR_100" | "ISO_IR 100" => Some(IsoIr100),
            "ISO_IR_101" | "ISO_IR 101" => Some(IsoIr101),
            "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr100 => Some(Box::new(IsoIr100CharacterSetCodec)),
            SpecificCharacterSet::IsoIr101 => Some(Box::new(IsoIr101CharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Data type representing the default character set.
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the ISO-IR 100 characters set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct IsoIr100CharacterSetCodec;

impl TextCodec for IsoIr100CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 100"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the ISO-IR 101 characters set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct IsoIr101CharacterSetCodec;

impl TextCodec for IsoIr101CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 101"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_2
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_2
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the UTF-8 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct Utf8CharacterSetCodec;

impl TextCodec for Utf8CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 192"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        UTF_8
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        UTF_8
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the GB18030 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy)]
pub struct Gb18030CharacterSetCodec;

impl TextCodec for Gb18030CharacterSetCodec {
    fn name(&self) -> &'static str {
        "GB18030"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        GB18030
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        GB18030
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

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

    #[test]
    fn iso_ir_6_baseline() {
        let codec = SpecificCharacterSet::Default
            .codec()
            .expect("Must be fully supported");
        assert_eq!(codec.decode(b"Smith^John").unwrap(), "Smith^John");
    }

    #[test]
    fn iso_ir_192_baseline() {
        let codec = SpecificCharacterSet::IsoIr192
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec.decode("Simões^John".as_bytes()).unwrap(),
            "Simões^John",
        );
        assert_eq!(
            codec.decode("Иванков^Андрей".as_bytes()).unwrap(),
            "Иванков^Андрей",
        );
    }

    #[test]
    fn iso_ir_100_baseline() {
        let codec = SpecificCharacterSet::IsoIr100
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"Sim\xF5es^Jo\xE3o").unwrap(), "Simões^João");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_101_baseline() {
        let codec = SpecificCharacterSet::IsoIr101
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }
}
<|endoftext|>