<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use energy::{PairPotential, PairRestriction};
use types::{Vector3D, Matrix3, One, Zero};

/// The different way to compute non-bonded pair interactions
#[derive(Clone, Copy, Debug)]
enum PairComputation {
    /// Using only a cutoff distance
    Cutoff,
    /// Using a cutoff distance and a shift
    Shifted(f64),
}

/// A non-bonded interaction between two particle.
///
/// This is a thin wrapper around a [`Box<PairPotential>`][PairPotential]
/// associated with a [pair restriction][PairRestriction]. It ensure that the
/// potential is computed up to a cutoff distance. An additional shifting of the
/// potential can be used in molecular dynamics, to ensure that the energy is
/// continuous at the cutoff distance.
///
/// [PairPotential]: trait.PairPotential.html
/// [PairRestriction]: enum.PairRestriction.html
#[derive(Clone)]
pub struct PairInteraction {
    /// The potential of this interaction
    potential: Box<PairPotential>,
    /// The associated pair restrictions
    restriction: PairRestriction,
    /// The cutoff distance
    cutoff: f64,
    /// Should we use tail corrections
    tail: bool,
    /// The computation mode
    computation: PairComputation,
}

impl PairInteraction {
    /// Create a new `PairInteraction` for the given `potential` and using the
    /// given `cutoff` distance.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), 0.525);
    /// // energy at and after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn new(potential: Box<PairPotential>, cutoff: f64) -> PairInteraction {
        PairInteraction {
            potential: potential,
            cutoff: cutoff,
            restriction: PairRestriction::None,
            computation: PairComputation::Cutoff,
            tail: false,
        }
    }

    /// Create a new `PairInteraction` with the given `cutoff`, using shifted
    /// computation of the energy.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::shifted(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), -4.2);
    ///
    /// // energy goes smoothly to zero at the cutoff
    /// assert!(interaction.energy(1.999).abs() < 0.01);
    /// // energy after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn shifted(potential: Box<PairPotential>, cutoff: f64) -> PairInteraction {
        let shift = potential.energy(cutoff);
        PairInteraction {
            potential: potential,
            cutoff: cutoff,
            restriction: PairRestriction::None,
            computation: PairComputation::Shifted(shift),
            tail: false,
        }
    }

    /// Enable the use of tail corrections for energy and virial contribution
    /// of this pair interaction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::LennardJones;
    ///
    /// let potential = Box::new(LennardJones{sigma: 0.5, epsilon: 4.2});
    /// let mut interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.tail_energy(), 0.0);
    ///
    /// interaction.enable_tail_corrections();
    /// assert!(interaction.tail_energy() < 0.0);
    /// ```
    pub fn enable_tail_corrections(&mut self) {
        self.tail = true;
    }

    /// Get the associated pair restriction. The default is to have no pair
    /// restriction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::{NullPotential, PairRestriction};
    /// let interaction = PairInteraction::new(Box::new(NullPotential), 2.0);
    ///
    /// assert_eq!(interaction.restriction(), PairRestriction::None);
    /// ```
    pub fn restriction(&self) -> PairRestriction {
        self.restriction
    }

    /// Set the pair restriction associated with this interaction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::{NullPotential, PairRestriction};
    /// let mut interaction = PairInteraction::new(Box::new(NullPotential), 2.0);
    ///
    /// assert_eq!(interaction.restriction(), PairRestriction::None);
    /// interaction.set_restriction(PairRestriction::Exclude12);
    /// assert_eq!(interaction.restriction(), PairRestriction::Exclude12);
    /// ```
    pub fn set_restriction(&mut self, restriction: PairRestriction) {
        self.restriction = restriction;
    }
}

impl PairInteraction {
    /// Get the energy for this pair interaction at the distance `r`.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), 0.525);
    /// // energy at and after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn energy(&self, r: f64) -> f64 {
        if r >= self.cutoff {
            0.0
        } else {
            let energy = self.potential.energy(r);
            match self.computation {
                PairComputation::Cutoff => energy,
                PairComputation::Shifted(shift) => energy - shift,
            }
        }
    }

    /// Get the norm of the force for this pair interaction at the distance `r`.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.force(1.0), -2.1);
    /// // force at and after the cutoff is zero
    /// assert_eq!(interaction.force(2.0), 0.0);
    /// ```
    pub fn force(&self, r: f64) -> f64 {
        if r >= self.cutoff {
            0.0
        } else {
            self.potential.force(r)
        }
    }

    /// Get the virial contribution for this pair interaction at the distance
    /// `r`
    pub fn virial(&self, r: &Vector3D) -> Matrix3 {
        if r.norm() >= self.cutoff {
            Matrix3::zero()
        } else {
            self.potential.virial(r)
        }
    }

    /// Get the tail correction to the energy for this pair interaction
    pub fn tail_energy(&self) -> f64 {
        if self.tail {
            self.potential.tail_energy(self.cutoff)
        } else {
            0.0
        }
    }

    /// Get the tail correction to the virial for this pair interaction
    pub fn tail_virial(&self) -> Matrix3 {
        if self.tail {
            let tensor = Matrix3::one() / 3.0;
            return self.potential.tail_virial(self.cutoff) * tensor;
        } else {
            return Matrix3::zero();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use energy::{NullPotential, LennardJones, PairRestriction};
    use energy::Potential;

    #[test]
    fn restriction() {
        let mut pairs = PairInteraction::new(Box::new(NullPotential), 10.0);
        assert_eq!(pairs.restriction(), PairRestriction::None);

        pairs.set_restriction(PairRestriction::Exclude13);
        assert_eq!(pairs.restriction(), PairRestriction::Exclude13);
    }

    #[test]
    fn cutoff() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let pairs = PairInteraction::new(Box::new(lj), 4.0);

        assert_eq!(pairs.force(2.5), lj.force(2.5));
        assert_eq!(pairs.energy(2.5), lj.energy(2.5));

        assert_eq!(pairs.force(4.1), 0.0);
        assert_eq!(pairs.energy(4.1), 0.0);
    }

    #[test]
    fn shifted() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let pairs = PairInteraction::shifted(Box::new(lj), 4.0);

        assert_eq!(pairs.force(2.5), lj.force(2.5));
        assert_approx_eq!(pairs.energy(2.5), -0.030681134109158216);

        assert_eq!(pairs.force(4.1), 0.0);
        assert_eq!(pairs.energy(4.1), 0.0);
    }

    #[test]
    fn tail_corrections() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let mut pairs = PairInteraction::shifted(Box::new(lj), 4.0);
        pairs.enable_tail_corrections();

        assert_eq!(pairs.tail_energy(), -0.041663275824652776);
        assert_approx_eq!(pairs.tail_virial().trace(), -0.24995930989583334);
    }
}
<commit_msg>Add missing examples<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use energy::{PairPotential, PairRestriction};
use types::{Vector3D, Matrix3, One, Zero};

/// The different way to compute non-bonded pair interactions
#[derive(Clone, Copy, Debug)]
enum PairComputation {
    /// Using only a cutoff distance
    Cutoff,
    /// Using a cutoff distance and a shift
    Shifted(f64),
}

/// A non-bonded interaction between two particle.
///
/// This is a thin wrapper around a [`Box<PairPotential>`][PairPotential]
/// associated with a [pair restriction][PairRestriction]. It ensure that the
/// potential is computed up to a cutoff distance. An additional shifting of the
/// potential can be used in molecular dynamics, to ensure that the energy is
/// continuous at the cutoff distance.
///
/// [PairPotential]: trait.PairPotential.html
/// [PairRestriction]: enum.PairRestriction.html
#[derive(Clone)]
pub struct PairInteraction {
    /// The potential of this interaction
    potential: Box<PairPotential>,
    /// The associated pair restrictions
    restriction: PairRestriction,
    /// The cutoff distance
    cutoff: f64,
    /// Should we use tail corrections
    tail: bool,
    /// The computation mode
    computation: PairComputation,
}

impl PairInteraction {
    /// Create a new `PairInteraction` for the given `potential` and using the
    /// given `cutoff` distance.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), 0.525);
    /// // energy at and after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn new(potential: Box<PairPotential>, cutoff: f64) -> PairInteraction {
        PairInteraction {
            potential: potential,
            cutoff: cutoff,
            restriction: PairRestriction::None,
            computation: PairComputation::Cutoff,
            tail: false,
        }
    }

    /// Create a new `PairInteraction` with the given `cutoff`, using shifted
    /// computation of the energy.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::shifted(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), -4.2);
    ///
    /// // energy goes smoothly to zero at the cutoff
    /// assert!(interaction.energy(1.999).abs() < 0.01);
    /// // energy after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn shifted(potential: Box<PairPotential>, cutoff: f64) -> PairInteraction {
        let shift = potential.energy(cutoff);
        PairInteraction {
            potential: potential,
            cutoff: cutoff,
            restriction: PairRestriction::None,
            computation: PairComputation::Shifted(shift),
            tail: false,
        }
    }

    /// Enable the use of tail corrections for energy and virial contribution
    /// of this pair interaction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::LennardJones;
    ///
    /// let potential = Box::new(LennardJones{sigma: 0.5, epsilon: 4.2});
    /// let mut interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.tail_energy(), 0.0);
    ///
    /// interaction.enable_tail_corrections();
    /// assert!(interaction.tail_energy() < 0.0);
    /// ```
    pub fn enable_tail_corrections(&mut self) {
        self.tail = true;
    }

    /// Get the associated pair restriction. The default is to have no pair
    /// restriction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::{NullPotential, PairRestriction};
    /// let interaction = PairInteraction::new(Box::new(NullPotential), 2.0);
    ///
    /// assert_eq!(interaction.restriction(), PairRestriction::None);
    /// ```
    pub fn restriction(&self) -> PairRestriction {
        self.restriction
    }

    /// Set the pair restriction associated with this interaction.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::{NullPotential, PairRestriction};
    /// let mut interaction = PairInteraction::new(Box::new(NullPotential), 2.0);
    ///
    /// assert_eq!(interaction.restriction(), PairRestriction::None);
    /// interaction.set_restriction(PairRestriction::Exclude12);
    /// assert_eq!(interaction.restriction(), PairRestriction::Exclude12);
    /// ```
    pub fn set_restriction(&mut self, restriction: PairRestriction) {
        self.restriction = restriction;
    }
}

impl PairInteraction {
    /// Get the energy for this pair interaction at the distance `r`.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.energy(1.0), 0.525);
    /// // energy at and after the cutoff is zero
    /// assert_eq!(interaction.energy(2.0), 0.0);
    /// ```
    pub fn energy(&self, r: f64) -> f64 {
        if r >= self.cutoff {
            0.0
        } else {
            let energy = self.potential.energy(r);
            match self.computation {
                PairComputation::Cutoff => energy,
                PairComputation::Shifted(shift) => energy - shift,
            }
        }
    }

    /// Get the norm of the force for this pair interaction at the distance `r`.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::new(potential, 2.0);
    ///
    /// assert_eq!(interaction.force(1.0), -2.1);
    /// // force at and after the cutoff is zero
    /// assert_eq!(interaction.force(2.0), 0.0);
    /// ```
    pub fn force(&self, r: f64) -> f64 {
        if r >= self.cutoff {
            0.0
        } else {
            self.potential.force(r)
        }
    }

    /// Get the virial contribution for this pair interaction at the distance
    /// `r`.
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::Harmonic;
    /// # use lumol::types::Vector3D;
    ///
    /// let potential = Box::new(Harmonic{x0: 0.5, k: 4.2});
    /// let interaction = PairInteraction::shifted(potential, 2.0);
    ///
    /// let r = Vector3D::new(1.0, 0.0, 0.3);
    /// let force = interaction.force(r.norm()) * r / r.norm();
    /// assert_eq!(interaction.virial(&r), r.tensorial(&force));
    /// ```
    pub fn virial(&self, r: &Vector3D) -> Matrix3 {
        if r.norm() >= self.cutoff {
            Matrix3::zero()
        } else {
            self.potential.virial(r)
        }
    }

    /// Get the tail correction to the energy for this pair interaction
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::LennardJones;
    ///
    /// let potential = Box::new(LennardJones{sigma: 0.5, epsilon: 4.2});
    /// let mut interaction = PairInteraction::new(potential, 2.0);
    /// interaction.enable_tail_corrections();
    ///
    /// assert_eq!(interaction.tail_energy(), -0.010936609903971353);
    /// ```
    pub fn tail_energy(&self) -> f64 {
        if self.tail {
            self.potential.tail_energy(self.cutoff)
        } else {
            0.0
        }
    }

    /// Get the tail correction to the virial for this pair interaction
    ///
    /// # Examples
    ///
    /// ```
    /// use lumol::energy::PairInteraction;
    /// use lumol::energy::LennardJones;
    /// # use lumol::types::Matrix3;
    ///
    /// let potential = Box::new(LennardJones{sigma: 0.5, epsilon: 4.2});
    /// let mut interaction = PairInteraction::new(potential, 2.0);
    /// interaction.enable_tail_corrections();
    ///
    /// let w = -0.02187143961588542;
    /// let virial = Matrix3::new(
    ///      w , 0.0, 0.0,
    ///     0.0,  w , 0.0,
    ///     0.0, 0.0,  w
    /// );
    ///
    /// assert_eq!(interaction.tail_virial(), virial);
    /// ```
    pub fn tail_virial(&self) -> Matrix3 {
        if self.tail {
            let tensor = Matrix3::one() / 3.0;
            return self.potential.tail_virial(self.cutoff) * tensor;
        } else {
            return Matrix3::zero();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use energy::{NullPotential, LennardJones, PairRestriction};
    use energy::Potential;

    #[test]
    fn restriction() {
        let mut pairs = PairInteraction::new(Box::new(NullPotential), 10.0);
        assert_eq!(pairs.restriction(), PairRestriction::None);

        pairs.set_restriction(PairRestriction::Exclude13);
        assert_eq!(pairs.restriction(), PairRestriction::Exclude13);
    }

    #[test]
    fn cutoff() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let pairs = PairInteraction::new(Box::new(lj), 4.0);

        assert_eq!(pairs.force(2.5), lj.force(2.5));
        assert_eq!(pairs.energy(2.5), lj.energy(2.5));

        assert_eq!(pairs.force(4.1), 0.0);
        assert_eq!(pairs.energy(4.1), 0.0);
    }

    #[test]
    fn shifted() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let pairs = PairInteraction::shifted(Box::new(lj), 4.0);

        assert_eq!(pairs.force(2.5), lj.force(2.5));
        assert_approx_eq!(pairs.energy(2.5), -0.030681134109158216);

        assert_eq!(pairs.force(4.1), 0.0);
        assert_eq!(pairs.energy(4.1), 0.0);
    }

    #[test]
    fn tail_corrections() {
        let lj = LennardJones{sigma: 1.0, epsilon: 2.0};
        let mut pairs = PairInteraction::shifted(Box::new(lj), 4.0);
        pairs.enable_tail_corrections();

        assert_eq!(pairs.tail_energy(), -0.041663275824652776);
        assert_approx_eq!(pairs.tail_virial().trace(), -0.24995930989583334);
    }
}
<|endoftext|>


<commit_before>use std::result::Result;
use std::collections::HashMap;

use gossyp_base::RetrieveToolError;
use gossyp_base::Environment;
use gossyp_base::Tool;

///
/// Errors that can occur when binding a variable
///
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub enum BindingError {
    /// The requested variable name is already in use
    AlreadyInUse,
}

///
/// Result of binding to an environment
///
pub enum BindingResult {
    /// Name maps to a variable
    Variable(u32),

    /// Name maps to a tool in the external environment
    Tool(Box<Tool>),

    /// Got an error while mapping a tool (binding isn't a tool or a variable)
    Error(RetrieveToolError)
}

///
/// A binding environment can be used to allocate variable values that will be used
/// during execution of a script.
///
struct BaseBindingEnvironment<'a> {
    /// The external environment that contains tools we can bind to
    environment: &'a Environment,

    /// The next variable value that will be alllocated
    next_to_allocate: u32,

    /// The current set of binding allocations
    bindings: HashMap<String, u32>
}

///
/// A child environment for a base environment
///
struct ChildBindingEnvironment<'short, 'long: 'short> {
    /// The base binding environment that this child environment is for
    base_environment: &'short mut BaseBindingEnvironment<'long>,

    /// The parent environment for this environment (used when looking up variables further up the heirarchy)
    parent_environment: Option<&'short ChildBindingEnvironment<'short, 'long>>,

    /// The current set of binding allocations
    bindings: HashMap<String, u32>
}

///
/// Trait implemented by objects that represent a binding environment
///
pub trait BindingEnvironment {
    ///
    /// Allocates a variable location without assigning a name
    ///
    fn allocate_location(&mut self) -> u32;

    ///
    /// Allocates a variable location with an assigned name (which must not
    /// already be in use)
    ///
    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError>;

    ///
    /// Looks up a variable location by name
    ///
    fn lookup(&self, name: &str) -> BindingResult;

    ///
    /// Returns the total number of variables allocated for this environment
    ///
    fn get_number_of_variables(&self) -> u32;

    ///
    /// Creates a sub environment
    ///
    /// This allows names to be re-used with new variables, but existing variables
    /// will continue to refer to their current locations
    ///
    fn create_sub_environment<'a>(&'a mut self) -> Box<BindingEnvironment + 'a>;
}

impl BindingEnvironment {
    ///
    /// Creates a new binding environment. New variables will be mapped from 0
    ///
    pub fn new<'a>(environment: &'a Environment) -> Box<BindingEnvironment+'a> {
        Box::new(BaseBindingEnvironment {
            environment:        environment,
            next_to_allocate:   0,
            bindings:           HashMap::new()
        })
    }
}

impl<'a> BindingEnvironment for BaseBindingEnvironment<'a> {
    ///
    /// Creates a new sub-environment, where new variable names can be a
    ///
    fn create_sub_environment<'b>(&'b mut self) -> Box<BindingEnvironment + 'b> {
        Box::new(ChildBindingEnvironment {
            base_environment:   self,
            parent_environment: None,
            bindings:           HashMap::new()
        })
    }

    ///
    /// Allocates a new variable location in this binding (without assigning a name to it)
    ///
    fn allocate_location(&mut self) -> u32 {
        // If there's no parent, just allocate directly
        let allocation          = self.next_to_allocate;
        self.next_to_allocate   = allocation + 1;

        allocation
    }

    ///
    /// Allocates a new variable
    ///
    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError> {
        let name_string = String::from(name);

        if self.bindings.contains_key(&name_string) {
            // Variable name is already taken
            Err(BindingError::AlreadyInUse)
        } else {
            // Can assign this location to value
            let allocation = self.allocate_location();
            self.bindings.insert(name_string, allocation);

            Ok(allocation)
        }
    }

    ///
    /// Looks up a name in this binding environment
    ///
    fn lookup(&self, name: &str) -> BindingResult {
        if let Some(variable) = self.bindings.get(&String::from(name)) {
            // Try to retrieve as a variable directly from this environment
            BindingResult::Variable(*variable)
        } else {
            // Try to retrieve from the environment
            let tool_or_error = self.environment.get_json_tool(name);

            match tool_or_error {
                Ok(tool)    => BindingResult::Tool(tool),
                Err(error)  => BindingResult::Error(error)
            }
        }
    }

    ///
    /// Returns the number of variables used in this environment
    ///
    fn get_number_of_variables(&self) -> u32 {
        self.next_to_allocate
    }
}

impl<'short, 'long> BindingEnvironment for ChildBindingEnvironment<'short, 'long> {
    fn allocate_location(&mut self) -> u32 {
        self.base_environment.allocate_location()
    }

    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError> {
        let name_string = String::from(name);

        if self.bindings.contains_key(&name_string) {
            // Variable name is already taken
            Err(BindingError::AlreadyInUse)
        } else {
            // Can assign this location to value
            let allocation = self.allocate_location();
            self.bindings.insert(name_string, allocation);

            Ok(allocation)
        }
    }

    fn lookup(&self, name: &str) -> BindingResult {
        unimplemented!()
    }

    fn get_number_of_variables(&self) -> u32 {
        self.base_environment.get_number_of_variables()
    }

    fn create_sub_environment<'b>(&'b mut self) -> Box<BindingEnvironment + 'b> {
        Box::new(ChildBindingEnvironment {
            parent_environment: None,
            base_environment:   self.base_environment,
            bindings:           HashMap::new()
        })
    }
}

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

    #[test]
    fn can_allocate_location() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);
    }

    #[test]
    fn can_allocate_many_locations() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);
        assert!(binding.allocate_location() == 1);
        assert!(binding.allocate_location() == 2);
    }

    #[test]
    fn can_get_number_of_variables() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_location();
        binding.allocate_location();
        binding.allocate_location();

        assert!(binding.get_number_of_variables() == 3);

        binding.allocate_location();

        assert!(binding.get_number_of_variables() == 4);
    }

    #[test]
    fn allocating_locations_in_child_environments_also_does_in_parent() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);

        {
            let mut child_environment = binding.create_sub_environment();

            assert!(child_environment.allocate_location() == 1);
        }

        assert!(binding.allocate_location() == 2);
    }

    #[test]
    fn can_allocate_variable_name() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_variable("test") == Ok(0));
    }

    #[test]
    fn cannot_allocate_variable_name_twice() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_variable("test") == Ok(0));
        assert!(binding.allocate_variable("test") == Err(BindingError::AlreadyInUse));
    }

    #[test]
    fn can_lookup_variable_name() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_variable("test");

        assert!(match binding.lookup("test") { BindingResult::Variable(v) => v == 0, _ => false });
    }

    #[test]
    fn can_lookup_many_variable_names() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_variable("test1");
        binding.allocate_variable("test2");
        binding.allocate_variable("test3");

        assert!(match binding.lookup("test1") { BindingResult::Variable(v) => v == 0, _ => false });
        assert!(match binding.lookup("test2") { BindingResult::Variable(v) => v == 1, _ => false });
        assert!(match binding.lookup("test3") { BindingResult::Variable(v) => v == 2, _ => false });
    }

    #[test]
    fn can_lookup_tool_name() {
        let tool_environment = DynamicEnvironment::new();
        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut binding = BindingEnvironment::new(&tool_environment);

        assert!(match binding.lookup("test") { BindingResult::Tool(_) => true, _ => false });
    }

    #[test]
    fn variable_name_has_precedence_over_tool() {
        let tool_environment = DynamicEnvironment::new();
        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut binding = BindingEnvironment::new(&tool_environment);

        binding.allocate_variable("test");

        assert!(match binding.lookup("test") { BindingResult::Variable(v) => v == 0, _ => false });
    }
}
<commit_msg>Fix up implementation of child environments<commit_after>use std::result::Result;
use std::collections::HashMap;

use gossyp_base::RetrieveToolError;
use gossyp_base::Environment;
use gossyp_base::Tool;

///
/// Errors that can occur when binding a variable
///
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
pub enum BindingError {
    /// The requested variable name is already in use
    AlreadyInUse,
}

///
/// Result of binding to an environment
///
pub enum BindingResult {
    /// Name maps to a variable
    Variable(u32),

    /// Name maps to a tool in the external environment
    Tool(Box<Tool>),

    /// Got an error while mapping a tool (binding isn't a tool or a variable)
    Error(RetrieveToolError)
}

///
/// A binding environment can be used to allocate variable values that will be used
/// during execution of a script.
///
struct BaseBindingEnvironment<'a> {
    /// The external environment that contains tools we can bind to
    environment: &'a Environment,

    /// The next variable value that will be alllocated
    next_to_allocate: u32,

    /// The current set of binding allocations
    bindings: HashMap<String, u32>
}

///
/// A child environment for a base environment
///
struct ChildBindingEnvironment<'a> {
    /// The base binding environment that this child environment is for
    base_environment: &'a mut BindingEnvironment,

    /// The current set of binding allocations
    bindings: HashMap<String, u32>
}

///
/// Trait implemented by objects that represent a binding environment
///
pub trait BindingEnvironment {
    ///
    /// Allocates a variable location without assigning a name
    ///
    fn allocate_location(&mut self) -> u32;

    ///
    /// Allocates a variable location with an assigned name (which must not
    /// already be in use)
    ///
    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError>;

    ///
    /// Looks up a variable location by name
    ///
    fn lookup(&self, name: &str) -> BindingResult;

    ///
    /// Returns the total number of variables allocated for this environment
    ///
    fn get_number_of_variables(&self) -> u32;

    ///
    /// Creates a sub environment
    ///
    /// This allows names to be re-used with new variables, but existing variables
    /// will continue to refer to their current locations
    ///
    fn create_sub_environment<'a>(&'a mut self) -> Box<BindingEnvironment + 'a>;
}

impl BindingEnvironment {
    ///
    /// Creates a new binding environment. New variables will be mapped from 0
    ///
    pub fn new<'a>(environment: &'a Environment) -> Box<BindingEnvironment+'a> {
        Box::new(BaseBindingEnvironment {
            environment:        environment,
            next_to_allocate:   0,
            bindings:           HashMap::new()
        })
    }
}

impl<'a> BindingEnvironment for BaseBindingEnvironment<'a> {
    ///
    /// Creates a new sub-environment, where new variable names can be a
    ///
    fn create_sub_environment<'b>(&'b mut self) -> Box<BindingEnvironment + 'b> {
        Box::new(ChildBindingEnvironment {
            base_environment:   self,
            bindings:           HashMap::new()
        })
    }

    ///
    /// Allocates a new variable location in this binding (without assigning a name to it)
    ///
    fn allocate_location(&mut self) -> u32 {
        // If there's no parent, just allocate directly
        let allocation          = self.next_to_allocate;
        self.next_to_allocate   = allocation + 1;

        allocation
    }

    ///
    /// Allocates a new variable
    ///
    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError> {
        if self.bindings.contains_key(name) {
            // Variable name is already taken
            Err(BindingError::AlreadyInUse)
        } else {
            // Can assign this location to value
            let allocation = self.allocate_location();
            self.bindings.insert(String::from(name), allocation);

            Ok(allocation)
        }
    }

    ///
    /// Looks up a name in this binding environment
    ///
    fn lookup(&self, name: &str) -> BindingResult {
        if let Some(variable) = self.bindings.get(name) {
            // Try to retrieve as a variable directly from this environment
            BindingResult::Variable(*variable)
        } else {
            // Try to retrieve from the environment
            let tool_or_error = self.environment.get_json_tool(name);

            match tool_or_error {
                Ok(tool)    => BindingResult::Tool(tool),
                Err(error)  => BindingResult::Error(error)
            }
        }
    }

    ///
    /// Returns the number of variables used in this environment
    ///
    fn get_number_of_variables(&self) -> u32 {
        self.next_to_allocate
    }
}

impl<'a> BindingEnvironment for ChildBindingEnvironment<'a> {
    fn allocate_location(&mut self) -> u32 {
        self.base_environment.allocate_location()
    }

    fn allocate_variable(&mut self, name: &str) -> Result<u32, BindingError> {
        if self.bindings.contains_key(name) {
            // Variable name is already taken
            Err(BindingError::AlreadyInUse)
        } else {
            // Can assign this location to value
            let allocation = self.allocate_location();
            self.bindings.insert(String::from(name), allocation);

            Ok(allocation)
        }
    }

    fn lookup(&self, name: &str) -> BindingResult {
        if let Some(variable) = self.bindings.get(name) {
            BindingResult::Variable(*variable)
        } else {
            self.base_environment.lookup(name)
        }
    }

    fn get_number_of_variables(&self) -> u32 {
        self.base_environment.get_number_of_variables()
    }

    fn create_sub_environment<'b>(&'b mut self) -> Box<BindingEnvironment + 'b> {
        Box::new(ChildBindingEnvironment {
            base_environment:   self,
            bindings:           HashMap::new()
        })
    }
}

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

    #[test]
    fn can_allocate_location() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);
    }

    #[test]
    fn can_allocate_many_locations() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);
        assert!(binding.allocate_location() == 1);
        assert!(binding.allocate_location() == 2);
    }

    #[test]
    fn can_get_number_of_variables() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_location();
        binding.allocate_location();
        binding.allocate_location();

        assert!(binding.get_number_of_variables() == 3);

        binding.allocate_location();

        assert!(binding.get_number_of_variables() == 4);
    }

    #[test]
    fn allocating_locations_in_child_environments_also_does_in_parent() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_location() == 0);

        {
            let mut child_environment = binding.create_sub_environment();

            assert!(child_environment.allocate_location() == 1);
        }

        assert!(binding.allocate_location() == 2);
    }

    #[test]
    fn can_allocate_variable_name() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_variable("test") == Ok(0));
    }

    #[test]
    fn cannot_allocate_variable_name_twice() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        assert!(binding.allocate_variable("test") == Ok(0));
        assert!(binding.allocate_variable("test") == Err(BindingError::AlreadyInUse));
    }

    #[test]
    fn can_lookup_variable_name() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_variable("test");

        assert!(match binding.lookup("test") { BindingResult::Variable(v) => v == 0, _ => false });
    }

    #[test]
    fn can_lookup_many_variable_names() {
        let empty_environment   = EmptyEnvironment::new();
        let mut binding         = BindingEnvironment::new(&empty_environment);

        binding.allocate_variable("test1");
        binding.allocate_variable("test2");
        binding.allocate_variable("test3");

        assert!(match binding.lookup("test1") { BindingResult::Variable(v) => v == 0, _ => false });
        assert!(match binding.lookup("test2") { BindingResult::Variable(v) => v == 1, _ => false });
        assert!(match binding.lookup("test3") { BindingResult::Variable(v) => v == 2, _ => false });
    }

    #[test]
    fn can_lookup_tool_name() {
        let tool_environment = DynamicEnvironment::new();
        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut binding = BindingEnvironment::new(&tool_environment);

        assert!(match binding.lookup("test") { BindingResult::Tool(_) => true, _ => false });
    }

    #[test]
    fn variable_name_has_precedence_over_tool() {
        let tool_environment = DynamicEnvironment::new();
        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut binding = BindingEnvironment::new(&tool_environment);

        binding.allocate_variable("test");

        assert!(match binding.lookup("test") { BindingResult::Variable(v) => v == 0, _ => false });
    }
}
<|endoftext|>


<commit_before>use futures_core::task::{local_waker_from_nonlocal, LocalWaker, Wake};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Number of times the waker was awoken.
///
/// See [`new_count_waker`] for usage.
#[derive(Debug)]
pub struct AwokenCount {
    inner: Arc<WakerInner>,
}

impl PartialEq<usize> for AwokenCount {
    fn eq(&self, other: &usize) -> bool {
        self.inner.count.load(Ordering::SeqCst) == *other
    }
}

#[derive(Debug)]
struct WakerInner {
    count: AtomicUsize,
}

impl Wake for WakerInner {
    fn wake(arc_self: &Arc<Self>) {
        let _ = arc_self.count.fetch_add(1, Ordering::SeqCst);
    }
}

/// Create a new [`LocalWaker`] that counts the number of times it's awoken.
///
/// [`LocalWaker`]: futures_core::task::LocalWaker
///
/// # Examples
///
/// ```
/// #![feature(futures_api)]
/// use futures_test::task::new_count_waker;
///
/// let (lw, count) = new_count_waker();
///
/// assert_eq!(count, 0);
///
/// lw.wake();
/// lw.wake();
///
/// assert_eq!(count, 2);
/// ```
pub fn new_count_waker() -> (LocalWaker, AwokenCount) {
    let inner = Arc::new(WakerInner { count: AtomicUsize::new(0) });
    (local_waker_from_nonlocal(inner.clone()), AwokenCount { inner })
}
<commit_msg>Add AwokenCount.get<commit_after>use futures_core::task::{local_waker_from_nonlocal, LocalWaker, Wake};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

/// Number of times the waker was awoken.
///
/// See [`new_count_waker`] for usage.
#[derive(Debug)]
pub struct AwokenCount {
    inner: Arc<WakerInner>,
}

impl AwokenCount {
    /// Get the current count.
    fn get(&self) -> usize {
        self.inner.count.load(Ordering::SeqCst)
    }
}

impl PartialEq<usize> for AwokenCount {
    fn eq(&self, other: &usize) -> bool {
        self.get() == *other
    }
}

#[derive(Debug)]
struct WakerInner {
    count: AtomicUsize,
}

impl Wake for WakerInner {
    fn wake(arc_self: &Arc<Self>) {
        let _ = arc_self.count.fetch_add(1, Ordering::SeqCst);
    }
}

/// Create a new [`LocalWaker`] that counts the number of times it's awoken.
///
/// [`LocalWaker`]: futures_core::task::LocalWaker
///
/// # Examples
///
/// ```
/// #![feature(futures_api)]
/// use futures_test::task::new_count_waker;
///
/// let (lw, count) = new_count_waker();
///
/// assert_eq!(count, 0);
///
/// lw.wake();
/// lw.wake();
///
/// assert_eq!(count, 2);
/// ```
pub fn new_count_waker() -> (LocalWaker, AwokenCount) {
    let inner = Arc::new(WakerInner { count: AtomicUsize::new(0) });
    (local_waker_from_nonlocal(inner.clone()), AwokenCount { inner })
}
<|endoftext|>


<commit_before>// P_2_1_3_05
//
// Generative Gestaltung – Creative Coding im Web
// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018
// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni
// with contributions by Joey Lee and Niels Poldervaart
// Copyright 2018
//
// http://www.generative-gestaltung.de
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * changing positions of stapled circles in a grid
 *
 * MOUSE
 * position x          : horizontal position shift
 * position y          : vertical position shift
 * left click          : random position shift
 *
 * KEYS
 * s                   : save png
 */
use nannou::prelude::*;
use nannou::rand::rngs::StdRng;
use nannou::rand::{Rng, SeedableRng};

fn main() {
    nannou::app(model).run();
}

struct Model {
    tile_count_x: u32,
    tile_count_y: u32,
    act_random_seed: u64,
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .size(600, 600)
        .view(view)
        .mouse_pressed(mouse_pressed)
        .build()
        .unwrap();

    Model {
        tile_count_x: 10,
        tile_count_y: 10,
        act_random_seed: 0,
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    let win = app.window_rect();

    draw.background().color(WHITE);
    let mut rng = StdRng::seed_from_u64(model.act_random_seed);

    let tile_width = win.w() / model.tile_count_x as f32;
    let tile_height = win.h() / model.tile_count_y as f32;
    let step_size = clamp(
        map_range(app.mouse.x, win.left(), win.right(), 0.0, win.w()),
        0.0,
        win.w(),
    ) / 10.0;
    let end_size = clamp(
        map_range(app.mouse.y, win.top(), win.bottom(), 0.0, win.h()),
        0.0,
        win.h(),
    ) / 10.0;
    let color_step = 6;

    for grid_y in 0..model.tile_count_y {
        for grid_x in 0..model.tile_count_x {
            let pos_x = (win.left() + (tile_width / 2.0)) + tile_width * grid_x as f32;
            let pos_y = (win.top() - (tile_height / 2.0)) - tile_height * grid_y as f32;

            //modules
            let heading = rng.gen_range(0, 4);

            for i in 0..step_size as usize {
                let radius = map_range(i, 0, step_size as usize, tile_width, end_size) / 2.0;
                let col = gray((255 - i * color_step) as f32 / 255.0);
                let (x, y) = match heading {
                    0 => (pos_x + i as f32, pos_y),
                    1 => (pos_x, pos_y + i as f32),
                    2 => (pos_x - i as f32, pos_y),
                    3 => (pos_x, pos_y - i as f32),
                    _ => (0.0, 0.0),
                };
                draw.ellipse()
                    .x_y(x, y)
                    .radius(radius)
                    .resolution(32)
                    .color(col);
            }
        }
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();
}

fn mouse_pressed(_app: &App, model: &mut Model, _button: MouseButton) {
    model.act_random_seed = (random_f32() * 100000.0) as u64;
}
<commit_msg>Fix overflow on p_2_1_3_05<commit_after>// P_2_1_3_05
//
// Generative Gestaltung – Creative Coding im Web
// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018
// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni
// with contributions by Joey Lee and Niels Poldervaart
// Copyright 2018
//
// http://www.generative-gestaltung.de
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * changing positions of stapled circles in a grid
 *
 * MOUSE
 * position x          : horizontal position shift
 * position y          : vertical position shift
 * left click          : random position shift
 *
 * KEYS
 * s                   : save png
 */
use nannou::prelude::*;
use nannou::rand::rngs::StdRng;
use nannou::rand::{Rng, SeedableRng};

fn main() {
    nannou::app(model).run();
}

struct Model {
    tile_count_x: u32,
    tile_count_y: u32,
    act_random_seed: u64,
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .size(600, 600)
        .view(view)
        .mouse_pressed(mouse_pressed)
        .build()
        .unwrap();

    Model {
        tile_count_x: 10,
        tile_count_y: 10,
        act_random_seed: 0,
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    let win = app.window_rect();

    draw.background().color(WHITE);
    let mut rng = StdRng::seed_from_u64(model.act_random_seed);

    let tile_width = win.w() / model.tile_count_x as f32;
    let tile_height = win.h() / model.tile_count_y as f32;
    let step_size = clamp(
        map_range(app.mouse.x, win.left(), win.right(), 0.0, win.w()),
        0.0,
        win.w(),
    ) / 10.0;
    let end_size = clamp(
        map_range(app.mouse.y, win.top(), win.bottom(), 0.0, win.h()),
        0.0,
        win.h(),
    ) / 10.0;
    let color_step = 6;

    for grid_y in 0..model.tile_count_y {
        for grid_x in 0..model.tile_count_x {
            let pos_x = (win.left() + (tile_width / 2.0)) + tile_width * grid_x as f32;
            let pos_y = (win.top() - (tile_height / 2.0)) - tile_height * grid_y as f32;

            //modules
            let heading = rng.gen_range(0, 4);

            for i in 0..step_size as usize {
                let radius = map_range(i, 0, step_size as usize, tile_width, end_size) / 2.0;
                let col = gray((255.0 - (i * color_step) as f32) / 255.0);
                let (x, y) = match heading {
                    0 => (pos_x + i as f32, pos_y),
                    1 => (pos_x, pos_y + i as f32),
                    2 => (pos_x - i as f32, pos_y),
                    3 => (pos_x, pos_y - i as f32),
                    _ => (0.0, 0.0),
                };
                draw.ellipse()
                    .x_y(x, y)
                    .radius(radius)
                    .resolution(32)
                    .color(col);
            }
        }
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();
}

fn mouse_pressed(_app: &App, model: &mut Model, _button: MouseButton) {
    model.act_random_seed = (random_f32() * 100000.0) as u64;
}
<|endoftext|>


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

use s = super::super::shade;
use super::gl;
use std::cell::Cell;

pub fn create_object(stage: s::Stage, data: &[u8])
        -> (Result<super::Shader, ()>, Option<String>) {
    let target = match stage {
        s::Vertex => gl::VERTEX_SHADER,
        s::Geometry => gl::GEOMETRY_SHADER,
        s::Fragment => gl::FRAGMENT_SHADER,
    };
    let name = gl::CreateShader(target);
    let mut length = data.len() as gl::types::GLint;
    unsafe {
        gl::ShaderSource(name, 1, &(data.as_ptr() as *gl::types::GLchar), &length);
    }
    gl::CompileShader(name);
    info!("\tCompiled shader {}", name);

    let status = query_shader_int(name, gl::COMPILE_STATUS);
    let mut length = query_shader_int(name, gl::INFO_LOG_LENGTH);

    let info = if length > 0 {
        let mut info = String::with_capacity(length as uint);
        info.grow(length as uint, 0u8 as char);
        unsafe {
            gl::GetShaderInfoLog(name, length, &mut length,
                info.as_slice().as_ptr() as *mut gl::types::GLchar);
        }
        info.truncate(length as uint);
        Some(info)
    } else {
        None
    };

    let name = if status != 0 { Ok(name) } else { Err(()) };

    (name, info)
}

fn query_shader_int(shader: super::Shader, query: gl::types::GLenum) -> gl::types::GLint {
    let mut ret = 0 as gl::types::GLint;
    unsafe {
        gl::GetShaderiv(shader, query, &mut ret);
    }
    ret
}

fn query_program_int(prog: super::Program, query: gl::types::GLenum) -> gl::types::GLint {
    let mut ret = 0 as gl::types::GLint;
    unsafe {
        gl::GetProgramiv(prog, query, &mut ret);
    }
    ret
}

enum StorageType {
    Var(s::BaseType, s::ContainerType),
    Sampler(s::BaseType, s::SamplerType),
    Unknown,
}

impl StorageType {
    fn new(storage: gl::types::GLenum) -> StorageType {
        match storage {
            gl::FLOAT                        => Var(s::BaseF32, s::Single),
            gl::FLOAT_VEC2                   => Var(s::BaseF32, s::Vector(2)),
            gl::FLOAT_VEC3                   => Var(s::BaseF32, s::Vector(3)),
            gl::FLOAT_VEC4                   => Var(s::BaseF32, s::Vector(4)),

            gl::INT                          => Var(s::BaseI32, s::Single),
            gl::INT_VEC2                     => Var(s::BaseI32, s::Vector(2)),
            gl::INT_VEC3                     => Var(s::BaseI32, s::Vector(3)),
            gl::INT_VEC4                     => Var(s::BaseI32, s::Vector(4)),

            gl::UNSIGNED_INT                 => Var(s::BaseU32, s::Single),
            gl::UNSIGNED_INT_VEC2            => Var(s::BaseU32, s::Vector(2)),
            gl::UNSIGNED_INT_VEC3            => Var(s::BaseU32, s::Vector(3)),
            gl::UNSIGNED_INT_VEC4            => Var(s::BaseU32, s::Vector(4)),

            gl::BOOL                         => Var(s::BaseBool, s::Single),
            gl::BOOL_VEC2                    => Var(s::BaseBool, s::Vector(2)),
            gl::BOOL_VEC3                    => Var(s::BaseBool, s::Vector(3)),
            gl::BOOL_VEC4                    => Var(s::BaseBool, s::Vector(4)),

            gl::FLOAT_MAT2                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 2)),
            gl::FLOAT_MAT3                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 3)),
            gl::FLOAT_MAT4                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 4)),
            gl::FLOAT_MAT2x3                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 3)),
            gl::FLOAT_MAT2x4                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 4)),
            gl::FLOAT_MAT3x2                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 2)),
            gl::FLOAT_MAT3x4                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 4)),
            gl::FLOAT_MAT4x2                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 2)),
            gl::FLOAT_MAT4x3                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 3)),

            // TODO: double matrices

            gl::SAMPLER_1D                   => Sampler(s::BaseF32, s::Sampler1D(s::NoArray, s::NoShadow)),
            gl::SAMPLER_1D_ARRAY             => Sampler(s::BaseF32, s::Sampler1D(s::Array,   s::NoShadow)),
            gl::SAMPLER_1D_SHADOW            => Sampler(s::BaseF32, s::Sampler1D(s::NoArray, s::Shadow)),
            gl::SAMPLER_1D_ARRAY_SHADOW      => Sampler(s::BaseF32, s::Sampler1D(s::Array,   s::Shadow)),

            gl::SAMPLER_2D                   => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_ARRAY             => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::NoShadow, s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_SHADOW            => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::Shadow,   s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_MULTISAMPLE       => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::MultiSample,   s::NoRect)),
            gl::SAMPLER_2D_RECT              => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::NoMultiSample, s::Rect)),
            gl::SAMPLER_2D_ARRAY_SHADOW      => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::Shadow,   s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_MULTISAMPLE_ARRAY => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::NoShadow, s::MultiSample,   s::NoRect)),
            gl::SAMPLER_2D_RECT_SHADOW       => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::Shadow,   s::NoMultiSample, s::Rect)),

            gl::SAMPLER_3D                   => Sampler(s::BaseF32, s::Sampler3D),
            gl::SAMPLER_CUBE                 => Sampler(s::BaseF32, s::SamplerCube(s::NoShadow)),
            gl::SAMPLER_CUBE_SHADOW          => Sampler(s::BaseF32, s::SamplerCube(s::Shadow)),

            // TODO: int samplers

            // TODO: unsigned samplers

            _ => Unknown,
        }
    }
}

fn query_attributes(prog: super::Program) -> Vec<s::Attribute> {
    let num     = query_program_int(prog, gl::ACTIVE_ATTRIBUTES);
    let max_len = query_program_int(prog, gl::ACTIVE_ATTRIBUTE_MAX_LENGTH);
    let mut name = String::with_capacity(max_len as uint);
    name.grow(max_len as uint, 0u8 as char);
    range(0, num as gl::types::GLuint).map(|i| {
        let mut length = 0 as gl::types::GLint;
        let mut size = 0 as gl::types::GLint;
        let mut storage = 0 as gl::types::GLenum;
        let loc = unsafe {
            let raw = name.as_slice().as_ptr() as *mut gl::types::GLchar;
            gl::GetActiveAttrib(prog, i, max_len, &mut length, &mut size, &mut storage, raw);
            gl::GetAttribLocation(prog, raw as *gl::types::GLchar)
        };
        let real_name = name.as_slice().slice_to(length as uint).to_string();
        let (base, container) = match StorageType::new(storage) {
            Var(b, c) => (b, c),
            _ => fail!("Unrecognized attribute storage: {}", storage)
        };
        info!("\t\tAttrib[{}] = '{}'\t{}\t{}", loc, real_name, base, container);
        s::Attribute {
            name: real_name,
            location: loc as uint,
            count: size as uint,
            base_type: base,
            container: container,
        }
    }).collect()
}

fn query_blocks(prog: super::Program) -> Vec<s::BlockVar> {
    let num     = query_program_int(prog, gl::ACTIVE_UNIFORM_BLOCKS);
    range(0, num as gl::types::GLuint).map(|i| {
        let mut length  = 0 as gl::types::GLint;
        let mut size    = 0 as gl::types::GLint;
        let mut tmp     = 0 as gl::types::GLint;
        let mut usage = 0u8;
        unsafe {
            gl::GetActiveUniformBlockiv(prog, i, gl::UNIFORM_BLOCK_NAME_LENGTH, &mut size);
            for (stage, &eval) in [gl::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
                    gl::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER].iter().enumerate() {
                gl::GetActiveUniformBlockiv(prog, i, eval, &mut tmp);
                if tmp != 0 {usage |= 1<<stage;}
            }
        }
        let mut name = String::with_capacity(size as uint); //includes terminating null
        name.grow(size as uint, 0u8 as char);
        let mut actual_name_size = 0 as gl::types::GLint;
        unsafe {
            gl::GetActiveUniformBlockName(prog, i, size, &mut actual_name_size,
                name.as_slice().as_ptr() as *mut gl::types::GLchar);
            gl::GetActiveUniformBlockiv(prog, i, gl::UNIFORM_BLOCK_DATA_SIZE, &mut size);
        }
        name.truncate(actual_name_size as uint);
        info!("\t\tBlock '{}' of size {}", name, size);
        s::BlockVar {
            name: name,
            size: size as uint,
            usage: usage,
            active_slot: Cell::new(0),
        }
    }).collect()
}

fn query_parameters(prog: super::Program) -> (Vec<s::UniformVar>, Vec<s::SamplerVar>) {
    let mut uniforms = Vec::new();
    let mut textures = Vec::new();
    let total_num = query_program_int(prog, gl::ACTIVE_UNIFORMS);
    let indices: Vec<gl::types::GLuint> = range(0, total_num as gl::types::GLuint).collect();
    let mut block_indices = Vec::from_elem(total_num as uint, 0 as gl::types::GLint);
    unsafe {
        gl::GetActiveUniformsiv(prog, total_num as gl::types::GLsizei,
            indices.as_slice().as_ptr(), gl::UNIFORM_BLOCK_INDEX,
            block_indices.as_mut_slice().as_mut_ptr());
        //TODO: UNIFORM_IS_ROW_MAJOR
    }
    // prepare the name string
    let max_len = query_program_int(prog, gl::ACTIVE_UNIFORM_MAX_LENGTH);
    let mut name = String::with_capacity(max_len as uint);
    name.grow(max_len as uint, 0u8 as char);
    // walk the indices
    for (&i, _) in indices.iter().zip(block_indices.iter()).filter(|&(_, &b)| b<0) {
        let mut length = 0 as gl::types::GLint;
        let mut size = 0 as gl::types::GLint;
        let mut storage = 0 as gl::types::GLenum;
        let loc = unsafe {
            let raw = name.as_slice().as_ptr() as *mut gl::types::GLchar;
            gl::GetActiveUniform(prog, i,
                max_len, &mut length, &mut size, &mut storage, raw);
            gl::GetUniformLocation(prog, raw as *gl::types::GLchar)
        };
        let real_name = name.as_slice().slice_to(length as uint).to_string();
        match StorageType::new(storage) {
            Var(base, container) => {
                info!("\t\tUniform[{}] = '{}'\t{}\t{}", loc, real_name, base, container);
                uniforms.push(s::UniformVar {
                    name: real_name,
                    location: loc as uint,
                    count: size as uint,
                    base_type: base,
                    container: container,
                    active_value: Cell::new(s::ValueUnitialized),
                });
            },
            Sampler(base, sam_type) => {
                info!("\t\tSampler[{}] = '{}'\t{}\t{}", loc, real_name, base, sam_type);
                textures.push(s::SamplerVar {
                    name: real_name,
                    location: loc as uint,
                    base_type: base,
                    sampler_type: sam_type,
                    active_slot: Cell::new(0),
                });
            },
            Unknown => fail!("Unrecognized uniform storage: {}", storage)
        }
    }
    (uniforms, textures)
}

pub fn create_program(shaders: &[super::Shader])
        -> (Result<s::ProgramMeta, ()>, Option<String>) {
    let name = gl::CreateProgram();
    for &sh in shaders.iter() {
        gl::AttachShader(name, sh);
    }
    gl::LinkProgram(name);
    info!("\tLinked program {}", name);

    // get info message
    let status      = query_program_int(name, gl::LINK_STATUS);
    let mut length  = query_program_int(name, gl::INFO_LOG_LENGTH);
    let info = if length > 0 {
        let mut info = String::with_capacity(length as uint);
        info.grow(length as uint, 0u8 as char);
        unsafe {
            gl::GetProgramInfoLog(name, length, &mut length,
                info.as_slice().as_ptr() as *mut gl::types::GLchar);
        }
        info.truncate(length as uint);
        Some(info)
    } else {
        None
    };

    let meta = if status != 0 {
        let (uniforms, textures) = query_parameters(name);
        let meta = s::ProgramMeta {
            name: name,
            attributes: query_attributes(name),
            uniforms: uniforms,
            blocks: query_blocks(name),
            textures: textures,
        };
        Ok(meta)
    } else {
        Err(())
    };

    (meta, info)
}
<commit_msg>Make function names more consistent with opengl<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use s = super::super::shade;
use super::gl;
use std::cell::Cell;

pub fn create_object(stage: s::Stage, data: &[u8])
        -> (Result<super::Shader, ()>, Option<String>) {
    let target = match stage {
        s::Vertex => gl::VERTEX_SHADER,
        s::Geometry => gl::GEOMETRY_SHADER,
        s::Fragment => gl::FRAGMENT_SHADER,
    };
    let name = gl::CreateShader(target);
    let mut length = data.len() as gl::types::GLint;
    unsafe {
        gl::ShaderSource(name, 1, &(data.as_ptr() as *gl::types::GLchar), &length);
    }
    gl::CompileShader(name);
    info!("\tCompiled shader {}", name);

    let status = get_shader_iv(name, gl::COMPILE_STATUS);
    let mut length = get_shader_iv(name, gl::INFO_LOG_LENGTH);

    let info = if length > 0 {
        let mut info = String::with_capacity(length as uint);
        info.grow(length as uint, 0u8 as char);
        unsafe {
            gl::GetShaderInfoLog(name, length, &mut length,
                info.as_slice().as_ptr() as *mut gl::types::GLchar);
        }
        info.truncate(length as uint);
        Some(info)
    } else {
        None
    };

    let name = if status != 0 { Ok(name) } else { Err(()) };

    (name, info)
}

fn get_shader_iv(shader: super::Shader, query: gl::types::GLenum) -> gl::types::GLint {
    let mut iv = 0;
    unsafe { gl::GetShaderiv(shader, query, &mut iv) };
    iv
}

fn get_program_iv(program: super::Program, query: gl::types::GLenum) -> gl::types::GLint {
    let mut iv = 0;
    unsafe { gl::GetProgramiv(program, query, &mut iv) };
    iv
}

enum StorageType {
    Var(s::BaseType, s::ContainerType),
    Sampler(s::BaseType, s::SamplerType),
    Unknown,
}

impl StorageType {
    fn new(storage: gl::types::GLenum) -> StorageType {
        match storage {
            gl::FLOAT                        => Var(s::BaseF32, s::Single),
            gl::FLOAT_VEC2                   => Var(s::BaseF32, s::Vector(2)),
            gl::FLOAT_VEC3                   => Var(s::BaseF32, s::Vector(3)),
            gl::FLOAT_VEC4                   => Var(s::BaseF32, s::Vector(4)),

            gl::INT                          => Var(s::BaseI32, s::Single),
            gl::INT_VEC2                     => Var(s::BaseI32, s::Vector(2)),
            gl::INT_VEC3                     => Var(s::BaseI32, s::Vector(3)),
            gl::INT_VEC4                     => Var(s::BaseI32, s::Vector(4)),

            gl::UNSIGNED_INT                 => Var(s::BaseU32, s::Single),
            gl::UNSIGNED_INT_VEC2            => Var(s::BaseU32, s::Vector(2)),
            gl::UNSIGNED_INT_VEC3            => Var(s::BaseU32, s::Vector(3)),
            gl::UNSIGNED_INT_VEC4            => Var(s::BaseU32, s::Vector(4)),

            gl::BOOL                         => Var(s::BaseBool, s::Single),
            gl::BOOL_VEC2                    => Var(s::BaseBool, s::Vector(2)),
            gl::BOOL_VEC3                    => Var(s::BaseBool, s::Vector(3)),
            gl::BOOL_VEC4                    => Var(s::BaseBool, s::Vector(4)),

            gl::FLOAT_MAT2                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 2)),
            gl::FLOAT_MAT3                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 3)),
            gl::FLOAT_MAT4                   => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 4)),
            gl::FLOAT_MAT2x3                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 3)),
            gl::FLOAT_MAT2x4                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 2, 4)),
            gl::FLOAT_MAT3x2                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 2)),
            gl::FLOAT_MAT3x4                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 3, 4)),
            gl::FLOAT_MAT4x2                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 2)),
            gl::FLOAT_MAT4x3                 => Var(s::BaseF32, s::Matrix(s::ColumnMajor, 4, 3)),

            // TODO: double matrices

            gl::SAMPLER_1D                   => Sampler(s::BaseF32, s::Sampler1D(s::NoArray, s::NoShadow)),
            gl::SAMPLER_1D_ARRAY             => Sampler(s::BaseF32, s::Sampler1D(s::Array,   s::NoShadow)),
            gl::SAMPLER_1D_SHADOW            => Sampler(s::BaseF32, s::Sampler1D(s::NoArray, s::Shadow)),
            gl::SAMPLER_1D_ARRAY_SHADOW      => Sampler(s::BaseF32, s::Sampler1D(s::Array,   s::Shadow)),

            gl::SAMPLER_2D                   => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_ARRAY             => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::NoShadow, s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_SHADOW            => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::Shadow,   s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_MULTISAMPLE       => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::MultiSample,   s::NoRect)),
            gl::SAMPLER_2D_RECT              => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::NoShadow, s::NoMultiSample, s::Rect)),
            gl::SAMPLER_2D_ARRAY_SHADOW      => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::Shadow,   s::NoMultiSample, s::NoRect)),
            gl::SAMPLER_2D_MULTISAMPLE_ARRAY => Sampler(s::BaseF32, s::Sampler2D(s::Array,   s::NoShadow, s::MultiSample,   s::NoRect)),
            gl::SAMPLER_2D_RECT_SHADOW       => Sampler(s::BaseF32, s::Sampler2D(s::NoArray, s::Shadow,   s::NoMultiSample, s::Rect)),

            gl::SAMPLER_3D                   => Sampler(s::BaseF32, s::Sampler3D),
            gl::SAMPLER_CUBE                 => Sampler(s::BaseF32, s::SamplerCube(s::NoShadow)),
            gl::SAMPLER_CUBE_SHADOW          => Sampler(s::BaseF32, s::SamplerCube(s::Shadow)),

            // TODO: int samplers

            // TODO: unsigned samplers

            _ => Unknown,
        }
    }
}

fn query_attributes(prog: super::Program) -> Vec<s::Attribute> {
    let num = get_program_iv(prog, gl::ACTIVE_ATTRIBUTES);
    let max_len = get_program_iv(prog, gl::ACTIVE_ATTRIBUTE_MAX_LENGTH);
    let mut name = String::with_capacity(max_len as uint);
    name.grow(max_len as uint, 0u8 as char);
    range(0, num as gl::types::GLuint).map(|i| {
        let mut length = 0 as gl::types::GLint;
        let mut size = 0 as gl::types::GLint;
        let mut storage = 0 as gl::types::GLenum;
        let loc = unsafe {
            let raw = name.as_slice().as_ptr() as *mut gl::types::GLchar;
            gl::GetActiveAttrib(prog, i, max_len, &mut length, &mut size, &mut storage, raw);
            gl::GetAttribLocation(prog, raw as *gl::types::GLchar)
        };
        let real_name = name.as_slice().slice_to(length as uint).to_string();
        let (base, container) = match StorageType::new(storage) {
            Var(b, c) => (b, c),
            _ => fail!("Unrecognized attribute storage: {}", storage)
        };
        info!("\t\tAttrib[{}] = '{}'\t{}\t{}", loc, real_name, base, container);
        s::Attribute {
            name: real_name,
            location: loc as uint,
            count: size as uint,
            base_type: base,
            container: container,
        }
    }).collect()
}

fn query_blocks(prog: super::Program) -> Vec<s::BlockVar> {
    let num = get_program_iv(prog, gl::ACTIVE_UNIFORM_BLOCKS);
    range(0, num as gl::types::GLuint).map(|i| {
        let mut length  = 0 as gl::types::GLint;
        let mut size    = 0 as gl::types::GLint;
        let mut tmp     = 0 as gl::types::GLint;
        let mut usage = 0u8;
        unsafe {
            gl::GetActiveUniformBlockiv(prog, i, gl::UNIFORM_BLOCK_NAME_LENGTH, &mut size);
            for (stage, &eval) in [gl::UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
                    gl::UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER].iter().enumerate() {
                gl::GetActiveUniformBlockiv(prog, i, eval, &mut tmp);
                if tmp != 0 {usage |= 1<<stage;}
            }
        }
        let mut name = String::with_capacity(size as uint); //includes terminating null
        name.grow(size as uint, 0u8 as char);
        let mut actual_name_size = 0 as gl::types::GLint;
        unsafe {
            gl::GetActiveUniformBlockName(prog, i, size, &mut actual_name_size,
                name.as_slice().as_ptr() as *mut gl::types::GLchar);
            gl::GetActiveUniformBlockiv(prog, i, gl::UNIFORM_BLOCK_DATA_SIZE, &mut size);
        }
        name.truncate(actual_name_size as uint);
        info!("\t\tBlock '{}' of size {}", name, size);
        s::BlockVar {
            name: name,
            size: size as uint,
            usage: usage,
            active_slot: Cell::new(0),
        }
    }).collect()
}

fn query_parameters(prog: super::Program) -> (Vec<s::UniformVar>, Vec<s::SamplerVar>) {
    let mut uniforms = Vec::new();
    let mut textures = Vec::new();
    let total_num = get_program_iv(prog, gl::ACTIVE_UNIFORMS);
    let indices: Vec<gl::types::GLuint> = range(0, total_num as gl::types::GLuint).collect();
    let mut block_indices = Vec::from_elem(total_num as uint, 0 as gl::types::GLint);
    unsafe {
        gl::GetActiveUniformsiv(prog, total_num as gl::types::GLsizei,
            indices.as_slice().as_ptr(), gl::UNIFORM_BLOCK_INDEX,
            block_indices.as_mut_slice().as_mut_ptr());
        //TODO: UNIFORM_IS_ROW_MAJOR
    }
    // prepare the name string
    let max_len = get_program_iv(prog, gl::ACTIVE_UNIFORM_MAX_LENGTH);
    let mut name = String::with_capacity(max_len as uint);
    name.grow(max_len as uint, 0u8 as char);
    // walk the indices
    for (&i, _) in indices.iter().zip(block_indices.iter()).filter(|&(_, &b)| b<0) {
        let mut length = 0 as gl::types::GLint;
        let mut size = 0 as gl::types::GLint;
        let mut storage = 0 as gl::types::GLenum;
        let loc = unsafe {
            let raw = name.as_slice().as_ptr() as *mut gl::types::GLchar;
            gl::GetActiveUniform(prog, i,
                max_len, &mut length, &mut size, &mut storage, raw);
            gl::GetUniformLocation(prog, raw as *gl::types::GLchar)
        };
        let real_name = name.as_slice().slice_to(length as uint).to_string();
        match StorageType::new(storage) {
            Var(base, container) => {
                info!("\t\tUniform[{}] = '{}'\t{}\t{}", loc, real_name, base, container);
                uniforms.push(s::UniformVar {
                    name: real_name,
                    location: loc as uint,
                    count: size as uint,
                    base_type: base,
                    container: container,
                    active_value: Cell::new(s::ValueUnitialized),
                });
            },
            Sampler(base, sam_type) => {
                info!("\t\tSampler[{}] = '{}'\t{}\t{}", loc, real_name, base, sam_type);
                textures.push(s::SamplerVar {
                    name: real_name,
                    location: loc as uint,
                    base_type: base,
                    sampler_type: sam_type,
                    active_slot: Cell::new(0),
                });
            },
            Unknown => fail!("Unrecognized uniform storage: {}", storage)
        }
    }
    (uniforms, textures)
}

pub fn create_program(shaders: &[super::Shader])
        -> (Result<s::ProgramMeta, ()>, Option<String>) {
    let name = gl::CreateProgram();
    for &sh in shaders.iter() {
        gl::AttachShader(name, sh);
    }
    gl::LinkProgram(name);
    info!("\tLinked program {}", name);

    // get info message
    let status = get_program_iv(name, gl::LINK_STATUS);
    let mut length  = get_program_iv(name, gl::INFO_LOG_LENGTH);
    let info = if length > 0 {
        let mut info = String::with_capacity(length as uint);
        info.grow(length as uint, 0u8 as char);
        unsafe {
            gl::GetProgramInfoLog(name, length, &mut length,
                info.as_slice().as_ptr() as *mut gl::types::GLchar);
        }
        info.truncate(length as uint);
        Some(info)
    } else {
        None
    };

    let meta = if status != 0 {
        let (uniforms, textures) = query_parameters(name);
        let meta = s::ProgramMeta {
            name: name,
            attributes: query_attributes(name),
            uniforms: uniforms,
            blocks: query_blocks(name),
            textures: textures,
        };
        Ok(meta)
    } else {
        Err(())
    };

    (meta, info)
}
<|endoftext|>


<commit_before>//! Command buffers.
//!
//! A command buffer collects a list of commands to be submitted to the device.
//! Each command buffer has specific capabilities for graphics, compute or transfer operations,
//! and can be either a "primary" command buffer or a "secondary" command buffer.  Operations
//! always start from a primary command buffer, but a primary command buffer can contain calls
//! to secondary command buffers that contain snippets of commands that do specific things, similar
//! to function calls.
//!
//! All the possible commands are implemented in the `RawCommandBuffer` trait, and then the `CommandBuffer`
//! and related types make a generic, strongly-typed wrapper around it that only expose the methods that
//! are valid for the capabilities it provides.

// TODO: Document pipelines and subpasses better.

use Backend;
use queue::capability::Supports;
use std::marker::PhantomData;

mod compute;
mod graphics;
mod raw;
mod render_pass;
mod transfer;

pub use self::graphics::*;
pub use self::raw::{
    ClearValueRaw, ClearColorRaw, ClearDepthStencilRaw, DescriptorSetOffset,
    RawCommandBuffer, CommandBufferFlags, Level as RawLevel, CommandBufferInheritanceInfo,
};
pub use self::render_pass::*;
pub use self::transfer::*;

use std::borrow::{Cow};

/// Trait indicating how many times a Submit object can be submitted to a command buffer.
pub trait Shot {
    ///
    const FLAGS: CommandBufferFlags;
}
/// Indicates a Submit that can only be submitted once.
pub enum OneShot { }
impl Shot for OneShot { const FLAGS: CommandBufferFlags = CommandBufferFlags::ONE_TIME_SUBMIT; }

/// Indicates a Submit that can be submitted multiple times.
pub enum MultiShot { }
impl Shot for MultiShot { const FLAGS: CommandBufferFlags = CommandBufferFlags::EMPTY; }

/// A trait indicating the level of a command buffer.
pub trait Level { }

/// Indicates a primary command buffer.

/// Vulkan describes a primary command buffer as one which can be directly submitted
/// to a queue, and can execute `Secondary` command buffers.
pub enum Primary { }
impl Level for Primary { }

/// Indicates a secondary command buffer.
///
/// Vulkan describes a secondary command buffer as one which cannot be directly submitted
/// to a queue, but can be executed by a primary command buffer. This allows
/// multiple secondary command buffers to be constructed which do specific
/// things and can then be composed together into primary command buffers.
pub enum Secondary { }
impl Level for Secondary { }

/// Thread-safe finished command buffer for submission.
pub struct Submit<B: Backend, C, S, L>(pub(crate) B::CommandBuffer, pub(crate) PhantomData<(C, S, L)>);
impl<B: Backend, C, S, L> Submit<B, C, S, L> {
    fn new(buffer: B::CommandBuffer) -> Self {
        Submit(buffer, PhantomData)
    }
}
unsafe impl<B: Backend, C, S, L> Send for Submit<B, C, S, L> {}

/// A trait representing a command buffer that can be added to a `Submission`.
pub unsafe trait Submittable<'a, B: Backend, C, L: Level> {
    /// Unwraps the object into its underlying command buffer.
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer>;
}

unsafe impl<'a, B: Backend, C, L: Level> Submittable<'a, B, C, L> for Submit<B, C, OneShot, L> {
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer> { Cow::Owned(self.0) }
}

unsafe impl<'a, B: Backend, C, L: Level> Submittable<'a, B, C, L> for &'a Submit<B, C, MultiShot, L> {
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer> { Cow::Borrowed(&self.0) }
}

/// A convenience alias for not typing out the full signature of a secondary command buffer.
#[allow(type_alias_bounds)]
pub type SecondaryCommandBuffer<'a, B: Backend, C, S: Shot = OneShot> = CommandBuffer<'a, B, C, S, Secondary>;

/// A strongly-typed command buffer that will only implement methods that are valid for the operations
/// it supports.
pub struct CommandBuffer<'a, B: Backend, C, S: Shot = OneShot, L: Level = Primary> {
    pub(crate) raw: &'a mut B::CommandBuffer,
    pub(crate) _marker: PhantomData<(C, S, L)>
}

impl<'a, B: Backend, C, S: Shot, L: Level> CommandBuffer<'a, B, C, S, L> {
    /// Create a new typed command buffer from a raw command pool.
    pub unsafe fn new(raw: &'a mut B::CommandBuffer) -> Self {
        CommandBuffer {
            raw: raw,
            _marker: PhantomData,
        }
    }

    /// Get a reference to the raw command buffer
    pub fn as_raw(&self) -> &B::CommandBuffer {
        &*self.raw
    }

    /// Get a mutable reference to the raw command buffer
    pub fn as_raw_mut(&mut self) -> &mut B::CommandBuffer {
        self.raw
    }

    /// Finish recording commands to the command buffers.
    ///
    /// The command buffer will be consumed and can't be modified further.
    /// The command pool must be reset to able to re-record commands.
    pub fn finish(self) -> Submit<B, C, S, L> {
        self.raw.finish();
        let raw = self.raw.clone();

        ::std::mem::forget(self);

        Submit::new(raw)
    }

    /// Downgrade a command buffer to a lesser capability type.
    ///
    /// This is safe as a downgraded version can't be `submit`'ed
    /// since `submit` requires `self` by move.
    pub fn downgrade<D>(&mut self) -> &mut CommandBuffer<'a, B, D, S>
    where
        C: Supports<D>
    {
        unsafe { ::std::mem::transmute(self) }
    }
}

impl<'a, B: Backend, C, S: Shot> CommandBuffer<'a, B, C, S, Primary> {
    /// Identical to the `RawCommandBuffer` method of the same name.
    pub fn execute_commands<I, K>(&mut self, submits: I)
    where
        I: IntoIterator,
        I::Item: Submittable<'a, B, K, Secondary>,
        C: Supports<K>,
    {
        let submits = submits.into_iter().collect::<Vec<_>>();
        self.raw.execute_commands(submits.into_iter().map(|submit| unsafe { submit.into_buffer() }));
    }
}

impl<'a, B: Backend, C, S: Shot, L: Level> Drop for CommandBuffer<'a, B, C, S, L> {
    fn drop(&mut self) {
        self.raw.finish();
    }
}

<commit_msg>Don't #[allow(type_alias_bounds)].<commit_after>//! Command buffers.
//!
//! A command buffer collects a list of commands to be submitted to the device.
//! Each command buffer has specific capabilities for graphics, compute or transfer operations,
//! and can be either a "primary" command buffer or a "secondary" command buffer.  Operations
//! always start from a primary command buffer, but a primary command buffer can contain calls
//! to secondary command buffers that contain snippets of commands that do specific things, similar
//! to function calls.
//!
//! All the possible commands are implemented in the `RawCommandBuffer` trait, and then the `CommandBuffer`
//! and related types make a generic, strongly-typed wrapper around it that only expose the methods that
//! are valid for the capabilities it provides.

// TODO: Document pipelines and subpasses better.

use Backend;
use queue::capability::Supports;
use std::marker::PhantomData;

mod compute;
mod graphics;
mod raw;
mod render_pass;
mod transfer;

pub use self::graphics::*;
pub use self::raw::{
    ClearValueRaw, ClearColorRaw, ClearDepthStencilRaw, DescriptorSetOffset,
    RawCommandBuffer, CommandBufferFlags, Level as RawLevel, CommandBufferInheritanceInfo,
};
pub use self::render_pass::*;
pub use self::transfer::*;

use std::borrow::{Cow};

/// Trait indicating how many times a Submit object can be submitted to a command buffer.
pub trait Shot {
    ///
    const FLAGS: CommandBufferFlags;
}
/// Indicates a Submit that can only be submitted once.
pub enum OneShot { }
impl Shot for OneShot { const FLAGS: CommandBufferFlags = CommandBufferFlags::ONE_TIME_SUBMIT; }

/// Indicates a Submit that can be submitted multiple times.
pub enum MultiShot { }
impl Shot for MultiShot { const FLAGS: CommandBufferFlags = CommandBufferFlags::EMPTY; }

/// A trait indicating the level of a command buffer.
pub trait Level { }

/// Indicates a primary command buffer.

/// Vulkan describes a primary command buffer as one which can be directly submitted
/// to a queue, and can execute `Secondary` command buffers.
pub enum Primary { }
impl Level for Primary { }

/// Indicates a secondary command buffer.
///
/// Vulkan describes a secondary command buffer as one which cannot be directly submitted
/// to a queue, but can be executed by a primary command buffer. This allows
/// multiple secondary command buffers to be constructed which do specific
/// things and can then be composed together into primary command buffers.
pub enum Secondary { }
impl Level for Secondary { }

/// Thread-safe finished command buffer for submission.
pub struct Submit<B: Backend, C, S, L>(pub(crate) B::CommandBuffer, pub(crate) PhantomData<(C, S, L)>);
impl<B: Backend, C, S, L> Submit<B, C, S, L> {
    fn new(buffer: B::CommandBuffer) -> Self {
        Submit(buffer, PhantomData)
    }
}
unsafe impl<B: Backend, C, S, L> Send for Submit<B, C, S, L> {}

/// A trait representing a command buffer that can be added to a `Submission`.
pub unsafe trait Submittable<'a, B: Backend, C, L: Level> {
    /// Unwraps the object into its underlying command buffer.
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer>;
}

unsafe impl<'a, B: Backend, C, L: Level> Submittable<'a, B, C, L> for Submit<B, C, OneShot, L> {
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer> { Cow::Owned(self.0) }
}

unsafe impl<'a, B: Backend, C, L: Level> Submittable<'a, B, C, L> for &'a Submit<B, C, MultiShot, L> {
    unsafe fn into_buffer(self) -> Cow<'a, B::CommandBuffer> { Cow::Borrowed(&self.0) }
}

/// A convenience alias for not typing out the full signature of a secondary command buffer.
pub type SecondaryCommandBuffer<'a, B, C, S = OneShot> = CommandBuffer<'a, B, C, S, Secondary>;

/// A strongly-typed command buffer that will only implement methods that are valid for the operations
/// it supports.
pub struct CommandBuffer<'a, B: Backend, C, S: Shot = OneShot, L: Level = Primary> {
    pub(crate) raw: &'a mut B::CommandBuffer,
    pub(crate) _marker: PhantomData<(C, S, L)>
}

impl<'a, B: Backend, C, S: Shot, L: Level> CommandBuffer<'a, B, C, S, L> {
    /// Create a new typed command buffer from a raw command pool.
    pub unsafe fn new(raw: &'a mut B::CommandBuffer) -> Self {
        CommandBuffer {
            raw: raw,
            _marker: PhantomData,
        }
    }

    /// Get a reference to the raw command buffer
    pub fn as_raw(&self) -> &B::CommandBuffer {
        &*self.raw
    }

    /// Get a mutable reference to the raw command buffer
    pub fn as_raw_mut(&mut self) -> &mut B::CommandBuffer {
        self.raw
    }

    /// Finish recording commands to the command buffers.
    ///
    /// The command buffer will be consumed and can't be modified further.
    /// The command pool must be reset to able to re-record commands.
    pub fn finish(self) -> Submit<B, C, S, L> {
        self.raw.finish();
        let raw = self.raw.clone();

        ::std::mem::forget(self);

        Submit::new(raw)
    }

    /// Downgrade a command buffer to a lesser capability type.
    ///
    /// This is safe as a downgraded version can't be `submit`'ed
    /// since `submit` requires `self` by move.
    pub fn downgrade<D>(&mut self) -> &mut CommandBuffer<'a, B, D, S>
    where
        C: Supports<D>
    {
        unsafe { ::std::mem::transmute(self) }
    }
}

impl<'a, B: Backend, C, S: Shot> CommandBuffer<'a, B, C, S, Primary> {
    /// Identical to the `RawCommandBuffer` method of the same name.
    pub fn execute_commands<I, K>(&mut self, submits: I)
    where
        I: IntoIterator,
        I::Item: Submittable<'a, B, K, Secondary>,
        C: Supports<K>,
    {
        let submits = submits.into_iter().collect::<Vec<_>>();
        self.raw.execute_commands(submits.into_iter().map(|submit| unsafe { submit.into_buffer() }));
    }
}

impl<'a, B: Backend, C, S: Shot, L: Level> Drop for CommandBuffer<'a, B, C, S, L> {
    fn drop(&mut self) {
        self.raw.finish();
    }
}

<|endoftext|>