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

//! Caching energy components for speeding up the energy computation in
//! Monte-Carlo simulations.
//!
//! In most of Monte-Carlo moves, only a very small subset of the system changes.
//! We can use that property to remove the need of recomputing most of the
//! energy components, by storing them and providing update callbacks.
use std::mem;

use super::System;
use types::{Vector3D, Array2};

/// Callback for updating a cache. It also take an `&mut System` argument for
/// updating the cache inside the global potentials.
type UpdateCallback = Box<Fn(&mut EnergyCache, &mut System)>;

/// This is a cache for energy computation.
///
/// Cache integrity is left up to the user of this structure: any function with
/// `update_` prefix must be called as needed to ensure cache consistency.
pub struct EnergyCache {
    /// 2-D array containing the pairs interactions between particles `i` and
    /// `j` at index `i, j`
    pairs_cache: Array2<f64>,
    /// Energy of all the pairs in the system
    pairs: f64,
    /// Energy of all the bonds in the system
    bonds: f64,
    /// Energy of all the angles in the system
    angles: f64,
    /// Energy of all the dihedrals angles in the system
    dihedrals: f64,
    /// Energy of coulombic interactions
    coulomb: f64,
    /// Energy of global interactions
    global: f64,
    /// Callback to be called to update the cache if the system is modified
    updater: Option<UpdateCallback>
}

impl Default for EnergyCache {
    fn default() -> EnergyCache {
        EnergyCache::new()
    }
}

impl EnergyCache {
    /// Create a new empty energy cache.
    pub fn new() -> EnergyCache {
        EnergyCache {
            pairs_cache: Array2::zeros((0, 0)),
            pairs: 0.0,
            bonds: 0.0,
            angles: 0.0,
            dihedrals: 0.0,
            coulomb: 0.0,
            global: 0.0,
            updater: None,
        }
    }

    /// Clear all values in the cache by setting them to 0
    fn clear(&mut self) {
        self.pairs_cache.assign(0.0);
        self.pairs = 0.0;
        self.bonds = 0.0;
        self.angles = 0.0;
        self.dihedrals = 0.0;
        self.coulomb = 0.0;
        self.global = 0.0;
    }

    /// Initialize the cache to be used with `system`. After a call to this
    /// function, the cache is only usable with the same system. To change
    /// the associated system, one must call this function again.
    pub fn init(&mut self, system: &System) {
        self.clear();
        self.pairs_cache.resize_if_different((system.size(), system.size()));

        let evaluator = system.energy_evaluator();

        for i in 0..system.size() {
            for j in (i + 1)..system.size() {
                let r = system.nearest_image(i, j).norm();
                let energy = evaluator.pair(r, i, j);
                self.pairs_cache[(i, j)] = energy;
                self.pairs_cache[(j, i)] = energy;
                self.pairs += energy;
            }
        }

        self.bonds = evaluator.bonds();
        self.angles = evaluator.angles();
        self.dihedrals = evaluator.dihedrals();
        self.coulomb = evaluator.coulomb();
        self.global = evaluator.global();
    }

    /// Get the cached energy
    pub fn energy(&self) -> f64 {
        let mut energy = 0.0;
        energy += self.pairs;

        energy += self.bonds;
        energy += self.angles;
        energy += self.dihedrals;

        energy += self.coulomb;
        energy += self.global;
        return energy;
    }

    /// Update the cache after a call to a `EnergyCache::*_cost` function or
    /// `EnergyCache::unused`.
    pub fn update(&mut self, system: &mut System) {
        let updater = mem::replace(&mut self.updater, None);
        if let Some(updater) = updater {
            updater(self, system);
        } else {
            fatal_error!("Error in `EnergyCache::update`: \
                         This function MUST be called after a call to a `*_cost` function");
        }
    }

    /// This function should be called whenever the cache is not used, but one
    /// still want it to be updated. Future call to `EnergyCache::update` will
    /// recompute the full cache.
    pub fn unused(&mut self) {
        self.updater = Some(Box::new(|cache, system| {
            cache.init(system);
        }))
    }
}

impl EnergyCache {
    /// Get the cost of moving the set of particles with indexes in `idxes` to
    /// `newpos`. This function DO NOT update the cache, the
    /// `update_particles_moved` function MUST be called if the particles are
    /// effectively moved.
    pub fn move_particles_cost(&mut self, system: &System, idxes: Vec<usize>, newpos: &[Vector3D]) -> f64 {
        let evaluator = system.energy_evaluator();

        // First, go for pair interactions
        let mut new_pairs = Array2::<f64>::zeros((system.size(), system.size()));
        let mut pairs_delta = 0.0;
        // Interactions with the sub-system not being moved
        for (i, &part_i) in idxes.iter().enumerate() {
            for part_j in 0..system.size() {
                // Exclude interactions inside the sub-system.
                if idxes.contains(&part_j) {continue}

                let r = system.cell().distance(&system[part_j].position, &newpos[i]);
                let energy = evaluator.pair(r, part_i, part_j);

                pairs_delta += energy;
                new_pairs[(part_i, part_j)] += energy;
                new_pairs[(part_j, part_i)] += energy;

                pairs_delta -= self.pairs_cache[(part_i, part_j)];
            }
        }

        // Interactions withing the sub-system being moved
        for (i, &part_i) in idxes.iter().enumerate() {
            for (j, &part_j) in idxes.iter().enumerate().skip(i + 1) {
                let r = system.cell().distance(&newpos[i], &newpos[j]);
                let energy = evaluator.pair(r, part_i, part_j);

                pairs_delta += energy;
                new_pairs[(part_i, part_j)] += energy;
                new_pairs[(part_j, part_i)] += energy;

                pairs_delta -= self.pairs_cache[(part_i, part_j)];
            }
        }

        // Recompute everything here. One day we could store some terms and do
        // the same thing than for pair interactions.
        let mut bonds = 0.0;
        let mut angles = 0.0;
        let mut dihedrals = 0.0;
        for molecule in system.molecules() {
            for bond in molecule.bonds() {
                let (i, j) = (bond.i(), bond.j());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let r = system.cell().distance(ri, rj);
                bonds += evaluator.bond(r, i, j);
            }

            for angle in molecule.angles() {
                let (i, j, k) = (angle.i(), angle.j(), angle.k());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let rk = new_position(system, k, &idxes, newpos);
                let theta = system.cell().angle(ri, rj, rk);
                angles += evaluator.angle(theta, i, j, k);
            }

            for dihedral in molecule.dihedrals() {
                let (i, j, k, m) = (dihedral.i(), dihedral.j(), dihedral.k(), dihedral.m());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let rk = new_position(system, k, &idxes, newpos);
                let rm = new_position(system, m, &idxes, newpos);
                let phi = system.cell().dihedral(ri, rj, rk, rm);
                dihedrals += evaluator.dihedral(phi, i, j, k, m);
            }
        }

        let coulomb_delta = if let Some(coulomb) = system.interactions().coulomb() {
            coulomb.borrow_mut().move_particles_cost(system, &idxes, newpos)
        } else {
            0.0
        };

        let mut global_delta = 0.0;
        for potential in system.interactions().globals() {
            global_delta += potential.borrow_mut().move_particles_cost(system, &idxes, newpos);
        }

        let cost = pairs_delta + (bonds - self.bonds)
                               + (angles - self.angles)
                               + (dihedrals - self.dihedrals)
                               + coulomb_delta + global_delta;

        self.updater = Some(Box::new(move |cache, system| {
            cache.bonds = bonds;
            cache.angles = angles;
            cache.dihedrals = dihedrals;

            cache.pairs += pairs_delta;
            cache.coulomb += coulomb_delta;
            cache.global += global_delta;

            let (n, m) = new_pairs.shape();
            debug_assert!(n == m);
            debug_assert!((n, m) == cache.pairs_cache.shape());
            for i in 0..n {
                for j in 0..n {
                    if new_pairs[(i, j)] != 0.0 {
                        cache.pairs_cache[(i, j)] = new_pairs[(i, j)];
                    }
                }
            }
            // Update the cache for the global potentials
            if let Some(coulomb) = system.interactions().coulomb() {
                coulomb.borrow_mut().update();
            }
            for potential in system.interactions().globals() {
                potential.borrow_mut().update();
            }
        }));
        return cost;
    }
}

/// Return either the new position of a particle (from `newpos`) if its index
/// is in `idxes`, or its old position in the system.
fn new_position<'a>(system: &'a System, i: usize, idxes: &[usize], newpos: &'a[Vector3D]) -> &'a Vector3D {
    for (idx, &particle) in idxes.iter().enumerate() {
        if particle == i {
            return &newpos[idx];
        }
    }
    return &system[i].position;
}

#[cfg(test)]
mod tests {
    use super::*;
    use sys::{System, UnitCell};
    use energy::*;
    use utils::{system_from_xyz, unit_from};
    use types::Vector3D;

    fn testing_system() -> System {
        let mut system = system_from_xyz("4
        bonds
        O     0.000000     0.000000     0.000000
        O     0.000000     0.000000     1.480000
        H     0.895669     0.000000    -0.316667
        H    -0.895669     0.000000     1.796667");
        system.set_cell(UnitCell::cubic(10.0));
        assert!(system.molecules().len() == 1);

        system.interactions_mut().add_pair("H", "H", PairInteraction::new(
            Box::new(LennardJones{sigma: 3.0, epsilon: unit_from(0.5, "kJ/mol")}), 3.0
        ));

        system.interactions_mut().add_pair("O", "O", PairInteraction::new(
            Box::new(NullPotential), 3.0
        ));

        system.interactions_mut().add_pair("O", "H", PairInteraction::new(
            Box::new(LennardJones{sigma: 1.0, epsilon: unit_from(0.3, "kJ/mol")}), 3.0
        ));

        system.interactions_mut().add_bond("O", "H",
            Box::new(Harmonic{x0: 3.4, k: unit_from(522.0, "kJ/mol/A^2")})
        );

        system.interactions_mut().add_angle("O", "O", "H",
            Box::new(Harmonic{x0: f64::to_radians(120.0), k: unit_from(150.0, "kJ/mol/deg^2")})
        );

        system.interactions_mut().add_dihedral("H", "O", "O", "H",
            Box::new(Harmonic{x0: f64::to_radians(180.0), k: unit_from(800.0, "kJ/mol/deg^2")})
        );

        system.interactions_mut().set_coulomb(Box::new(Wolf::new(8.0)));

        for atom in &mut system {
            if atom.name() == "O" {
                atom.charge = -0.5;
            } else if atom.name() == "H" {
                atom.charge = 0.5;
            }
        }

        return system;
    }

    #[test]
    fn cache_energy() {
        let system = testing_system();
        let mut cache = EnergyCache::new();
        cache.init(&system);

        assert_approx_eq!(cache.energy(), system.potential_energy());
    }

    #[test]
    fn move_atoms() {
        let mut system = testing_system();
        let mut cache = EnergyCache::new();
        let old_e = system.potential_energy();
        cache.init(&system);

        let idxes = vec![0, 3];
        let newpos = &[Vector3D::new(0.0, 0.0, 0.5), Vector3D::new(-0.7, 0.2, 1.5)];

        let cost = cache.move_particles_cost(&system, idxes, newpos);

        system[0].position = newpos[0];
        system[3].position = newpos[1];
        let new_e = system.potential_energy();
        assert_approx_eq!(cost, new_e - old_e, 1e-14);

        cache.update(&mut system);
        assert_approx_eq!(cache.energy(), new_e, 1e-14);

        // Check that the cache is really updated
        let old_e = new_e;
        let idxes = vec![2, 3];
        let newpos = &[Vector3D::new(0.9, 0.2, -0.4), Vector3D::new(-0.9, 0.0, 1.8)];
        let cost = cache.move_particles_cost(&system, idxes, newpos);
        system[2].position = newpos[0];
        system[3].position = newpos[1];
        let new_e = system.potential_energy();
        assert_approx_eq!(cost, new_e - old_e, 1e-14);
    }
}
<commit_msg>Fixed bug in update closure<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Caching energy components for speeding up the energy computation in
//! Monte-Carlo simulations.
//!
//! In most of Monte-Carlo moves, only a very small subset of the system changes.
//! We can use that property to remove the need of recomputing most of the
//! energy components, by storing them and providing update callbacks.
use std::mem;

use super::System;
use types::{Vector3D, Array2};

/// Callback for updating a cache. It also take an `&mut System` argument for
/// updating the cache inside the global potentials.
type UpdateCallback = Box<Fn(&mut EnergyCache, &mut System)>;

/// This is a cache for energy computation.
///
/// Cache integrity is left up to the user of this structure: any function with
/// `update_` prefix must be called as needed to ensure cache consistency.
pub struct EnergyCache {
    /// 2-D array containing the pairs interactions between particles `i` and
    /// `j` at index `i, j`
    pairs_cache: Array2<f64>,
    /// Energy of all the pairs in the system
    pairs: f64,
    /// Energy of all the bonds in the system
    bonds: f64,
    /// Energy of all the angles in the system
    angles: f64,
    /// Energy of all the dihedrals angles in the system
    dihedrals: f64,
    /// Energy of coulombic interactions
    coulomb: f64,
    /// Energy of global interactions
    global: f64,
    /// Callback to be called to update the cache if the system is modified
    updater: Option<UpdateCallback>
}

impl Default for EnergyCache {
    fn default() -> EnergyCache {
        EnergyCache::new()
    }
}

impl EnergyCache {
    /// Create a new empty energy cache.
    pub fn new() -> EnergyCache {
        EnergyCache {
            pairs_cache: Array2::zeros((0, 0)),
            pairs: 0.0,
            bonds: 0.0,
            angles: 0.0,
            dihedrals: 0.0,
            coulomb: 0.0,
            global: 0.0,
            updater: None,
        }
    }

    /// Clear all values in the cache by setting them to 0
    fn clear(&mut self) {
        self.pairs_cache.assign(0.0);
        self.pairs = 0.0;
        self.bonds = 0.0;
        self.angles = 0.0;
        self.dihedrals = 0.0;
        self.coulomb = 0.0;
        self.global = 0.0;
    }

    /// Initialize the cache to be used with `system`. After a call to this
    /// function, the cache is only usable with the same system. To change
    /// the associated system, one must call this function again.
    pub fn init(&mut self, system: &System) {
        self.clear();
        self.pairs_cache.resize_if_different((system.size(), system.size()));

        let evaluator = system.energy_evaluator();

        for i in 0..system.size() {
            for j in (i + 1)..system.size() {
                let r = system.nearest_image(i, j).norm();
                let energy = evaluator.pair(r, i, j);
                self.pairs_cache[(i, j)] = energy;
                self.pairs_cache[(j, i)] = energy;
                self.pairs += energy;
            }
        }

        self.bonds = evaluator.bonds();
        self.angles = evaluator.angles();
        self.dihedrals = evaluator.dihedrals();
        self.coulomb = evaluator.coulomb();
        self.global = evaluator.global();
    }

    /// Get the cached energy
    pub fn energy(&self) -> f64 {
        let mut energy = 0.0;
        energy += self.pairs;

        energy += self.bonds;
        energy += self.angles;
        energy += self.dihedrals;

        energy += self.coulomb;
        energy += self.global;
        return energy;
    }

    /// Update the cache after a call to a `EnergyCache::*_cost` function or
    /// `EnergyCache::unused`.
    pub fn update(&mut self, system: &mut System) {
        let updater = mem::replace(&mut self.updater, None);
        if let Some(updater) = updater {
            updater(self, system);
        } else {
            fatal_error!("Error in `EnergyCache::update`: \
                         This function MUST be called after a call to a `*_cost` function");
        }
    }

    /// This function should be called whenever the cache is not used, but one
    /// still want it to be updated. Future call to `EnergyCache::update` will
    /// recompute the full cache.
    pub fn unused(&mut self) {
        self.updater = Some(Box::new(|cache, system| {
            cache.init(system);
        }))
    }
}

impl EnergyCache {
    /// Get the cost of moving the set of particles with indexes in `idxes` to
    /// `newpos`. This function DO NOT update the cache, the
    /// `update_particles_moved` function MUST be called if the particles are
    /// effectively moved.
    pub fn move_particles_cost(&mut self, system: &System, idxes: Vec<usize>, newpos: &[Vector3D]) -> f64 {
        let evaluator = system.energy_evaluator();

        // First, go for pair interactions
        let mut new_pairs = Array2::<f64>::zeros((system.size(), system.size()));
        let mut pairs_delta = 0.0;
        // Interactions with the sub-system not being moved
        for (i, &part_i) in idxes.iter().enumerate() {
            for part_j in 0..system.size() {
                // Exclude interactions inside the sub-system.
                if idxes.contains(&part_j) {continue}

                let r = system.cell().distance(&system[part_j].position, &newpos[i]);
                let energy = evaluator.pair(r, part_i, part_j);

                pairs_delta += energy;
                new_pairs[(part_i, part_j)] += energy;
                new_pairs[(part_j, part_i)] += energy;

                pairs_delta -= self.pairs_cache[(part_i, part_j)];
            }
        }

        // Recompute everything here. One day we could store some terms and do
        // the same thing than for pair interactions.
        let mut bonds = 0.0;
        let mut angles = 0.0;
        let mut dihedrals = 0.0;
        for molecule in system.molecules() {
            for bond in molecule.bonds() {
                let (i, j) = (bond.i(), bond.j());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let r = system.cell().distance(ri, rj);
                bonds += evaluator.bond(r, i, j);
            }

            for angle in molecule.angles() {
                let (i, j, k) = (angle.i(), angle.j(), angle.k());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let rk = new_position(system, k, &idxes, newpos);
                let theta = system.cell().angle(ri, rj, rk);
                angles += evaluator.angle(theta, i, j, k);
            }

            for dihedral in molecule.dihedrals() {
                let (i, j, k, m) = (dihedral.i(), dihedral.j(), dihedral.k(), dihedral.m());
                let ri = new_position(system, i, &idxes, newpos);
                let rj = new_position(system, j, &idxes, newpos);
                let rk = new_position(system, k, &idxes, newpos);
                let rm = new_position(system, m, &idxes, newpos);
                let phi = system.cell().dihedral(ri, rj, rk, rm);
                dihedrals += evaluator.dihedral(phi, i, j, k, m);
            }
        }

        let coulomb_delta = if let Some(coulomb) = system.interactions().coulomb() {
            coulomb.borrow_mut().move_particles_cost(system, &idxes, newpos)
        } else {
            0.0
        };

        let mut global_delta = 0.0;
        for potential in system.interactions().globals() {
            global_delta += potential.borrow_mut().move_particles_cost(system, &idxes, newpos);
        }

        let cost = pairs_delta + (bonds - self.bonds)
                               + (angles - self.angles)
                               + (dihedrals - self.dihedrals)
                               + coulomb_delta + global_delta;

        self.updater = Some(Box::new(move |cache, system| {
            cache.bonds = bonds;
            cache.angles = angles;
            cache.dihedrals = dihedrals;

            cache.pairs += pairs_delta;
            cache.coulomb += coulomb_delta;
            cache.global += global_delta;

            let (n, m) = new_pairs.shape();
            debug_assert!(n == m);
            debug_assert!((n, m) == cache.pairs_cache.shape());
            // only loop over the indices that actually changed
            for i in idxes.iter() {
                for j in 0..n {
                    if idxes.contains(&j) {continue}
                    cache.pairs_cache[(*i, j)] = new_pairs[(*i, j)];
                    cache.pairs_cache[(j, *i)] = new_pairs[(*i, j)];
                }
            }
            // Update the cache for the global potentials
            if let Some(coulomb) = system.interactions().coulomb() {
                coulomb.borrow_mut().update();
            }
            for potential in system.interactions().globals() {
                potential.borrow_mut().update();
            }
        }));
        return cost;
    }
}

/// Return either the new position of a particle (from `newpos`) if its index
/// is in `idxes`, or its old position in the system.
fn new_position<'a>(system: &'a System, i: usize, idxes: &[usize], newpos: &'a[Vector3D]) -> &'a Vector3D {
    for (idx, &particle) in idxes.iter().enumerate() {
        if particle == i {
            return &newpos[idx];
        }
    }
    return &system[i].position;
}

#[cfg(test)]
mod tests {
    use super::*;
    use sys::{System, UnitCell};
    use energy::*;
    use utils::{system_from_xyz, unit_from};
    use types::Vector3D;

    fn testing_system() -> System {
        let mut system = system_from_xyz("4
        bonds
        O     0.000000     0.000000     0.000000
        O     0.000000     0.000000     1.480000
        H     0.895669     0.000000    -0.316667
        H    -0.895669     0.000000     1.796667");
        system.set_cell(UnitCell::cubic(10.0));
        assert!(system.molecules().len() == 1);

        system.interactions_mut().add_pair("H", "H", PairInteraction::new(
            Box::new(LennardJones{sigma: 3.0, epsilon: unit_from(0.5, "kJ/mol")}), 3.0
        ));

        system.interactions_mut().add_pair("O", "O", PairInteraction::new(
            Box::new(NullPotential), 3.0
        ));

        system.interactions_mut().add_pair("O", "H", PairInteraction::new(
            Box::new(LennardJones{sigma: 1.0, epsilon: unit_from(0.3, "kJ/mol")}), 3.0
        ));

        system.interactions_mut().add_bond("O", "H",
            Box::new(Harmonic{x0: 3.4, k: unit_from(522.0, "kJ/mol/A^2")})
        );

        system.interactions_mut().add_angle("O", "O", "H",
            Box::new(Harmonic{x0: f64::to_radians(120.0), k: unit_from(150.0, "kJ/mol/deg^2")})
        );

        system.interactions_mut().add_dihedral("H", "O", "O", "H",
            Box::new(Harmonic{x0: f64::to_radians(180.0), k: unit_from(800.0, "kJ/mol/deg^2")})
        );

        system.interactions_mut().set_coulomb(Box::new(Wolf::new(8.0)));

        for atom in &mut system {
            if atom.name() == "O" {
                atom.charge = -0.5;
            } else if atom.name() == "H" {
                atom.charge = 0.5;
            }
        }

        return system;
    }

    #[test]
    fn cache_energy() {
        let system = testing_system();
        let mut cache = EnergyCache::new();
        cache.init(&system);

        assert_approx_eq!(cache.energy(), system.potential_energy());
    }

    #[test]
    fn move_atoms() {
        let mut system = testing_system();
        let mut cache = EnergyCache::new();
        let old_e = system.potential_energy();
        cache.init(&system);

        let idxes = vec![0, 3];
        let newpos = &[Vector3D::new(0.0, 0.0, 0.5), Vector3D::new(-0.7, 0.2, 1.5)];

        let cost = cache.move_particles_cost(&system, idxes, newpos);

        system[0].position = newpos[0];
        system[3].position = newpos[1];
        let new_e = system.potential_energy();
        assert_approx_eq!(cost, new_e - old_e, 1e-14);

        cache.update(&mut system);
        assert_approx_eq!(cache.energy(), new_e, 1e-14);

        // Check that the cache is really updated
        let old_e = new_e;
        let idxes = vec![2, 3];
        let newpos = &[Vector3D::new(0.9, 0.2, -0.4), Vector3D::new(-0.9, 0.0, 1.8)];
        let cost = cache.move_particles_cost(&system, idxes, newpos);
        system[2].position = newpos[0];
        system[3].position = newpos[1];
        let new_e = system.potential_energy();
        assert_approx_eq!(cost, new_e - old_e, 1e-14);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille 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.

//! Dispatch a request to another HTTP server.
//!
//! This module provides functionnalities to dispatch a request to another server. This can be
//! used to make rouille behave as a reverse proxy.
//!
//! This function call will return immediately after the remote server has finished sending its
//! headers. The socket to the remote will be stored in the `ResponseBody` of the response.
//!
//! # Proxy() vs full_proxy()
//!
//! The difference between `proxy()` and `full_proxy()` is that if the target server fails to
//! return a proper error, the `proxy()` function will return an error (in the form of a
//! `ProxyError`) while the `full_proxy()` will return a `Response` with a status code indicating
//! an error.
//!
//! The `full_proxy()` function will only return an error if the body was already extracted from
//! the request before it was called. Since this indicates a logic error in the code, it is a good
//! idea to `unwrap()` the `Result` returned by `full_proxy()`.
//!
//! # Example
//!
//! You can for example dispatch to a different server depending on the host requested by the
//! client.
//!
//! ```
//! use rouille::{Request, Response};
//! use rouille::proxy;
//!
//! fn handle_request(request: &Request) -> Response {
//!     let config = match request.header("Host") {
//!         Some(h) if h == "domain1.com" => {
//!             proxy::ProxyConfig {
//!                 addr: "domain1.handler.localnetwork",
//!                 replace_host: None,
//!             }
//!         },
//!
//!         Some(h) if h == "domain2.com" => {
//!             proxy::ProxyConfig {
//!                 addr: "domain2.handler.localnetwork",
//!                 replace_host: None,
//!             }
//!         },
//!
//!         _ => return Response::empty_404()
//!     };
//!
//!     proxy::full_proxy(request, config).unwrap()
//! }
//! ```

use std::borrow::Cow;
use std::error;
use std::fmt;
use std::io;
use std::io::Error as IoError;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::net::TcpStream;
use std::net::ToSocketAddrs;

use Request;
use Response;
use ResponseBody;

/// Error that can happen when dispatching the request to another server.
#[derive(Debug)]
pub enum ProxyError {
    /// Can't pass through the body of the request because it was already extracted.
    BodyAlreadyExtracted,

    /// Could not read the body from the request, or could not connect to the remote server, or
    /// the connection to the remote server closed unexpectedly.
    IoError(IoError),

    /// The destination server didn't produce compliant HTTP.
    HttpParseError,
}

impl From<IoError> for ProxyError {
    fn from(err: IoError) -> ProxyError {
        ProxyError::IoError(err)
    }
}

impl error::Error for ProxyError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            ProxyError::BodyAlreadyExtracted => {
                "the body of the request was already extracted"
            },
            ProxyError::IoError(_) => {
                "could not read the body from the request, or could not connect to the remote \
                 server, or the connection to the remote server closed unexpectedly"
            },
            ProxyError::HttpParseError => {
                "the destination server didn't produce compliant HTTP"
            },
        }
    }

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

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

/// Configuration for the reverse proxy.
#[derive(Debug, Clone)]
pub struct ProxyConfig<A> {
    /// The address to connect to. For example `example.com:80`.
    pub addr: A,
    /// If `Some`, the `Host` header will be replaced with this value.
    pub replace_host: Option<Cow<'static, str>>,
}

/// Sends the request to another HTTP server using the configuration.
///
/// If the function fails to get a response from the target, an error is returned. If you want
/// to instead return a response with a status code such as 502 (`Bad Gateway`) or 504
/// (`Gateway Time-out`), see `full_proxy`.
///
/// > **Note**: Implementation is very hacky for the moment.
///
/// > **Note**: SSL is not supported.
// TODO: ^
pub fn proxy<A>(request: &Request, config: ProxyConfig<A>) -> Result<Response, ProxyError>
    where A: ToSocketAddrs
{
    let mut socket = try!(TcpStream::connect(config.addr));

    let mut data = match request.data() {
        Some(d) => d,
        None => return Err(ProxyError::BodyAlreadyExtracted),
    };

    try!(socket.write_all(format!("{} {} HTTP/1.1\n", request.method(), request.raw_url()).as_bytes()));
    for (header, value) in request.headers() {
        let value = if header == "Host" {
            if let Some(ref replace) = config.replace_host {
                &**replace
            } else {
                value
            }
        } else {
            value
        };

        try!(socket.write_all(format!("{}: {}\n", header, value).as_bytes()));
    }
    try!(socket.write_all("Connection: close\n\n".as_bytes()));
    try!(io::copy(&mut data, &mut socket));

    let mut socket = io::BufReader::new(socket);

    let mut headers = Vec::new();
    let status;
    {
        let mut lines = socket.by_ref().lines();

        {
            let line = try!(match lines.next() {
                Some(l) => l,
                None => return Err(ProxyError::HttpParseError),
            });
            let mut splits = line.splitn(3, ' ');
            let _ = splits.next();
            let status_str = match splits.next() {
                Some(l) => l,
                None => return Err(ProxyError::HttpParseError),
            };
            status = match status_str.parse() {
                Ok(s) => s,
                Err(_) => return Err(ProxyError::HttpParseError),
            };
        }

        for header in lines {
            let header = try!(header);
            if header.is_empty() { break; }

            let mut splits = header.splitn(2, ':');
            let header = match splits.next() {
                Some(v) => v,
                None => return Err(ProxyError::HttpParseError),
            };
            let val = match splits.next() {
                Some(v) => v,
                None => return Err(ProxyError::HttpParseError),
            };
            let val = &val[1..];

            headers.push((header.to_owned().into(), val.to_owned().into()));
        }
    }

    Ok(Response {
        status_code: status,
        headers: headers,
        data: ResponseBody::from_reader(socket),
        upgrade: None,
    })
}

/// Error that can happen when calling `full_proxy`.
#[derive(Debug)]
pub enum FullProxyError {
    /// Can't pass through the body of the request because it was already extracted.
    BodyAlreadyExtracted,
}

impl error::Error for FullProxyError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            FullProxyError::BodyAlreadyExtracted => {
                "the body of the request was already extracted"
            },
        }
    }
}

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

/// Sends the request to another HTTP server using the configuration.
///
/// Contrary to `proxy`, if the server fails to return a proper response then a response is
/// generated with the status code 502 or 504.
///
/// The only possible remaining error is if the body of the request was already extracted. Since
/// this would be a logic error, it is acceptable to unwrap it.
pub fn full_proxy<A>(request: &Request, config: ProxyConfig<A>) -> Result<Response, FullProxyError>
    where A: ToSocketAddrs
{
    match proxy(request, config) {
        Ok(r) => Ok(r),
        Err(ProxyError::IoError(_)) => Ok(Response::text("Gateway Time-out").with_status_code(504)),
        Err(ProxyError::HttpParseError) => Ok(Response::text("Bad Gateway").with_status_code(502)),
        Err(ProxyError::BodyAlreadyExtracted) => Err(FullProxyError::BodyAlreadyExtracted),
    }
}
<commit_msg>Add a timeout to the proxy<commit_after>// Copyright (c) 2016 The Rouille 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.

//! Dispatch a request to another HTTP server.
//!
//! This module provides functionnalities to dispatch a request to another server. This can be
//! used to make rouille behave as a reverse proxy.
//!
//! This function call will return immediately after the remote server has finished sending its
//! headers. The socket to the remote will be stored in the `ResponseBody` of the response.
//!
//! # Proxy() vs full_proxy()
//!
//! The difference between `proxy()` and `full_proxy()` is that if the target server fails to
//! return a proper error, the `proxy()` function will return an error (in the form of a
//! `ProxyError`) while the `full_proxy()` will return a `Response` with a status code indicating
//! an error.
//!
//! The `full_proxy()` function will only return an error if the body was already extracted from
//! the request before it was called. Since this indicates a logic error in the code, it is a good
//! idea to `unwrap()` the `Result` returned by `full_proxy()`.
//!
//! # Example
//!
//! You can for example dispatch to a different server depending on the host requested by the
//! client.
//!
//! ```
//! use rouille::{Request, Response};
//! use rouille::proxy;
//!
//! fn handle_request(request: &Request) -> Response {
//!     let config = match request.header("Host") {
//!         Some(h) if h == "domain1.com" => {
//!             proxy::ProxyConfig {
//!                 addr: "domain1.handler.localnetwork",
//!                 replace_host: None,
//!             }
//!         },
//!
//!         Some(h) if h == "domain2.com" => {
//!             proxy::ProxyConfig {
//!                 addr: "domain2.handler.localnetwork",
//!                 replace_host: None,
//!             }
//!         },
//!
//!         _ => return Response::empty_404()
//!     };
//!
//!     proxy::full_proxy(request, config).unwrap()
//! }
//! ```

use std::borrow::Cow;
use std::error;
use std::fmt;
use std::io;
use std::io::Error as IoError;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;
use std::net::TcpStream;
use std::net::ToSocketAddrs;
use std::time::Duration;

use Request;
use Response;
use ResponseBody;

/// Error that can happen when dispatching the request to another server.
#[derive(Debug)]
pub enum ProxyError {
    /// Can't pass through the body of the request because it was already extracted.
    BodyAlreadyExtracted,

    /// Could not read the body from the request, or could not connect to the remote server, or
    /// the connection to the remote server closed unexpectedly.
    IoError(IoError),

    /// The destination server didn't produce compliant HTTP.
    HttpParseError,
}

impl From<IoError> for ProxyError {
    fn from(err: IoError) -> ProxyError {
        ProxyError::IoError(err)
    }
}

impl error::Error for ProxyError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            ProxyError::BodyAlreadyExtracted => {
                "the body of the request was already extracted"
            },
            ProxyError::IoError(_) => {
                "could not read the body from the request, or could not connect to the remote \
                 server, or the connection to the remote server closed unexpectedly"
            },
            ProxyError::HttpParseError => {
                "the destination server didn't produce compliant HTTP"
            },
        }
    }

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

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

/// Configuration for the reverse proxy.
#[derive(Debug, Clone)]
pub struct ProxyConfig<A> {
    /// The address to connect to. For example `example.com:80`.
    pub addr: A,
    /// If `Some`, the `Host` header will be replaced with this value.
    pub replace_host: Option<Cow<'static, str>>,
}

/// Sends the request to another HTTP server using the configuration.
///
/// If the function fails to get a response from the target, an error is returned. If you want
/// to instead return a response with a status code such as 502 (`Bad Gateway`) or 504
/// (`Gateway Time-out`), see `full_proxy`.
///
/// > **Note**: Implementation is very hacky for the moment.
///
/// > **Note**: SSL is not supported.
// TODO: ^
pub fn proxy<A>(request: &Request, config: ProxyConfig<A>) -> Result<Response, ProxyError>
    where A: ToSocketAddrs
{
    let mut socket = try!(TcpStream::connect(config.addr));
    try!(socket.set_read_timeout(Some(Duration::from_secs(60))));
    try!(socket.set_write_timeout(Some(Duration::from_secs(60))));

    let mut data = match request.data() {
        Some(d) => d,
        None => return Err(ProxyError::BodyAlreadyExtracted),
    };

    try!(socket.write_all(format!("{} {} HTTP/1.1\n", request.method(), request.raw_url()).as_bytes()));
    for (header, value) in request.headers() {
        let value = if header == "Host" {
            if let Some(ref replace) = config.replace_host {
                &**replace
            } else {
                value
            }
        } else {
            value
        };

        try!(socket.write_all(format!("{}: {}\n", header, value).as_bytes()));
    }
    try!(socket.write_all("Connection: close\n\n".as_bytes()));
    try!(io::copy(&mut data, &mut socket));

    let mut socket = io::BufReader::new(socket);

    let mut headers = Vec::new();
    let status;
    {
        let mut lines = socket.by_ref().lines();

        {
            let line = try!(match lines.next() {
                Some(l) => l,
                None => return Err(ProxyError::HttpParseError),
            });
            let mut splits = line.splitn(3, ' ');
            let _ = splits.next();
            let status_str = match splits.next() {
                Some(l) => l,
                None => return Err(ProxyError::HttpParseError),
            };
            status = match status_str.parse() {
                Ok(s) => s,
                Err(_) => return Err(ProxyError::HttpParseError),
            };
        }

        for header in lines {
            let header = try!(header);
            if header.is_empty() { break; }

            let mut splits = header.splitn(2, ':');
            let header = match splits.next() {
                Some(v) => v,
                None => return Err(ProxyError::HttpParseError),
            };
            let val = match splits.next() {
                Some(v) => v,
                None => return Err(ProxyError::HttpParseError),
            };
            let val = &val[1..];

            headers.push((header.to_owned().into(), val.to_owned().into()));
        }
    }

    Ok(Response {
        status_code: status,
        headers: headers,
        data: ResponseBody::from_reader(socket),
        upgrade: None,
    })
}

/// Error that can happen when calling `full_proxy`.
#[derive(Debug)]
pub enum FullProxyError {
    /// Can't pass through the body of the request because it was already extracted.
    BodyAlreadyExtracted,
}

impl error::Error for FullProxyError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            FullProxyError::BodyAlreadyExtracted => {
                "the body of the request was already extracted"
            },
        }
    }
}

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

/// Sends the request to another HTTP server using the configuration.
///
/// Contrary to `proxy`, if the server fails to return a proper response then a response is
/// generated with the status code 502 or 504.
///
/// The only possible remaining error is if the body of the request was already extracted. Since
/// this would be a logic error, it is acceptable to unwrap it.
pub fn full_proxy<A>(request: &Request, config: ProxyConfig<A>) -> Result<Response, FullProxyError>
    where A: ToSocketAddrs
{
    match proxy(request, config) {
        Ok(r) => Ok(r),
        Err(ProxyError::IoError(_)) => Ok(Response::text("Gateway Time-out").with_status_code(504)),
        Err(ProxyError::HttpParseError) => Ok(Response::text("Bad Gateway").with_status_code(502)),
        Err(ProxyError::BodyAlreadyExtracted) => Err(FullProxyError::BodyAlreadyExtracted),
    }
}
<|endoftext|>


<commit_before>use ffi::*;

use pipeline::Pipeline;
use element::Element;
use ::Transfer;
use reference::Reference;

use std::ops::{Deref, DerefMut};

unsafe impl Sync for PlayBin {}
unsafe impl Send for PlayBin {}

pub struct PlayBin{
    playbin: Pipeline
}

impl PlayBin{
    pub fn new(name: &str) -> Option<PlayBin>{
        let pipeline = Element::new("playbin",name);
        match pipeline{
            Some(p) => {
                match unsafe{ Pipeline::new_from_gst_pipeline( p.transfer() as *mut GstPipeline) }{
                    Some(p) => Some(PlayBin{ playbin: p }),
                    None => None
                }
            }
            None => None
        }
    }

    pub fn set_audio_sink(&mut self, audio_sink: &Element){
        self.set("audio-sink", audio_sink);
    }

    /*pub fn frame(&self) -> GBuffer{
        GBuffer::new(playbin.get<GstBuffer*>("frame"))
    }*/

    pub fn set_subtitle_font_desc(&mut self, font: &str){
        self.set("subtitle-font-desc", font);
    }

    pub fn set_video_sink(&mut self, video_sink: &Element){
        self.set("video-sink", video_sink);
    }

    pub fn set_vis_plugin(&mut self, vis_plugin: &Element){
        self.set("vis-plugin", vis_plugin);
    }

    pub fn set_volume(&mut self, volume: f64){
        self.set("volume", volume);
    }

    pub fn set_connection_speed(&mut self, connection_speed: u64){
        self.set("connection-speed",connection_speed);
    }

    pub fn set_av_offset(&mut self, av_offset: i64){
        self.set("av-offset", av_offset);
    }

    pub fn set_buffer_duration(&mut self, buffer_duration: i64){
        self.set("buffer-duration",buffer_duration);
    }

    pub fn set_current_audio(&mut self, current_audio: i32){
        self.set("current-audio",current_audio);
    }

    pub fn set_current_text(&mut self, current_text: i32){
        self.set("current-text", current_text);
    }

    /*pub fn set_flags(&self, flags: GstPlayFlags){
        self.set("flags", flags);
    }*/

    pub fn mute(&mut self){
        self.set("mute", 1 as gboolean);
    }

    pub fn unmute(&mut self){
        self.set("mute", 0 as gboolean);
    }

    pub fn set_ring_buffer_max_size(&mut self, ring_buffer_max_size: u64){
        self.set("ring-buffer-max-size", ring_buffer_max_size);
    }

    pub fn set_source(&mut self, source: &Element){
        self.set("source", source);
    }

    pub fn set_subtitle_encoding(&mut self, encoding: &str){
        self.set("subtitle-encoding", encoding);
    }

    pub fn set_suburi(&mut self, suburi: &str){
        self.set("suburi", suburi);
    }

    pub fn set_text_sink(&mut self, textsink: &Element){
        self.set("text-sink", textsink);
    }

    pub fn set_uri(&mut self, uri: &str){
        self.set("uri", uri);
    }

    pub fn set_force_aspect_ratio(&mut self, force_aspect_ratio: bool){
        self.set("force-aspect-ratio", force_aspect_ratio as gboolean);
    }

    pub fn set_audio_stream_combiner(&mut self, audio_stream_combiner: &Element){
        self.set("audio-stream-combiner", audio_stream_combiner);
    }

    pub fn set_video_stream_combiner(&mut self, video_stream_combiner: &Element){
        self.set("vide-stream-combiner", video_stream_combiner);
    }

    pub fn set_flags(&mut self, flags: i32){
        self.set("flags", flags);
    }
}

impl ::Transfer for PlayBin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.playbin.transfer()
    }
}

impl Reference for PlayBin{
    fn reference(&self) -> PlayBin{
        PlayBin{ playbin: self.playbin.reference()}
    }
}

impl AsRef<Pipeline> for PlayBin{
    fn as_ref(&self) -> &Pipeline{
        &self.playbin
    }
}

impl AsMut<Pipeline> for PlayBin{
    fn as_mut(&mut self) -> &mut Pipeline{
        &mut self.playbin
    }
}

impl From<PlayBin> for Pipeline{
    fn from(b: PlayBin) -> Pipeline{
        b.playbin
    }
}

impl Deref for PlayBin{
    type Target = Pipeline;
    fn deref(&self) -> &Pipeline{
        &self.playbin
    }
}

impl DerefMut for PlayBin{
    fn deref_mut(&mut self) -> &mut Pipeline{
        &mut self.playbin
    }
}
<commit_msg>Playbin: fix typo<commit_after>use ffi::*;

use pipeline::Pipeline;
use element::Element;
use ::Transfer;
use reference::Reference;

use std::ops::{Deref, DerefMut};

unsafe impl Sync for PlayBin {}
unsafe impl Send for PlayBin {}

pub struct PlayBin{
    playbin: Pipeline
}

impl PlayBin{
    pub fn new(name: &str) -> Option<PlayBin>{
        let pipeline = Element::new("playbin",name);
        match pipeline{
            Some(p) => {
                match unsafe{ Pipeline::new_from_gst_pipeline( p.transfer() as *mut GstPipeline) }{
                    Some(p) => Some(PlayBin{ playbin: p }),
                    None => None
                }
            }
            None => None
        }
    }

    pub fn set_audio_sink(&mut self, audio_sink: &Element){
        self.set("audio-sink", audio_sink);
    }

    /*pub fn frame(&self) -> GBuffer{
        GBuffer::new(playbin.get<GstBuffer*>("frame"))
    }*/

    pub fn set_subtitle_font_desc(&mut self, font: &str){
        self.set("subtitle-font-desc", font);
    }

    pub fn set_video_sink(&mut self, video_sink: &Element){
        self.set("video-sink", video_sink);
    }

    pub fn set_vis_plugin(&mut self, vis_plugin: &Element){
        self.set("vis-plugin", vis_plugin);
    }

    pub fn set_volume(&mut self, volume: f64){
        self.set("volume", volume);
    }

    pub fn set_connection_speed(&mut self, connection_speed: u64){
        self.set("connection-speed",connection_speed);
    }

    pub fn set_av_offset(&mut self, av_offset: i64){
        self.set("av-offset", av_offset);
    }

    pub fn set_buffer_duration(&mut self, buffer_duration: i64){
        self.set("buffer-duration",buffer_duration);
    }

    pub fn set_current_audio(&mut self, current_audio: i32){
        self.set("current-audio",current_audio);
    }

    pub fn set_current_text(&mut self, current_text: i32){
        self.set("current-text", current_text);
    }

    /*pub fn set_flags(&self, flags: GstPlayFlags){
        self.set("flags", flags);
    }*/

    pub fn mute(&mut self){
        self.set("mute", 1 as gboolean);
    }

    pub fn unmute(&mut self){
        self.set("mute", 0 as gboolean);
    }

    pub fn set_ring_buffer_max_size(&mut self, ring_buffer_max_size: u64){
        self.set("ring-buffer-max-size", ring_buffer_max_size);
    }

    pub fn set_source(&mut self, source: &Element){
        self.set("source", source);
    }

    pub fn set_subtitle_encoding(&mut self, encoding: &str){
        self.set("subtitle-encoding", encoding);
    }

    pub fn set_suburi(&mut self, suburi: &str){
        self.set("suburi", suburi);
    }

    pub fn set_text_sink(&mut self, textsink: &Element){
        self.set("text-sink", textsink);
    }

    pub fn set_uri(&mut self, uri: &str){
        self.set("uri", uri);
    }

    pub fn set_force_aspect_ratio(&mut self, force_aspect_ratio: bool){
        self.set("force-aspect-ratio", force_aspect_ratio as gboolean);
    }

    pub fn set_audio_stream_combiner(&mut self, audio_stream_combiner: &Element){
        self.set("audio-stream-combiner", audio_stream_combiner);
    }

    pub fn set_video_stream_combiner(&mut self, video_stream_combiner: &Element){
        self.set("video-stream-combiner", video_stream_combiner);
    }

    pub fn set_flags(&mut self, flags: i32){
        self.set("flags", flags);
    }
}

impl ::Transfer for PlayBin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.playbin.transfer()
    }
}

impl Reference for PlayBin{
    fn reference(&self) -> PlayBin{
        PlayBin{ playbin: self.playbin.reference()}
    }
}

impl AsRef<Pipeline> for PlayBin{
    fn as_ref(&self) -> &Pipeline{
        &self.playbin
    }
}

impl AsMut<Pipeline> for PlayBin{
    fn as_mut(&mut self) -> &mut Pipeline{
        &mut self.playbin
    }
}

impl From<PlayBin> for Pipeline{
    fn from(b: PlayBin) -> Pipeline{
        b.playbin
    }
}

impl Deref for PlayBin{
    type Target = Pipeline;
    fn deref(&self) -> &Pipeline{
        &self.playbin
    }
}

impl DerefMut for PlayBin{
    fn deref_mut(&mut self) -> &mut Pipeline{
        &mut self.playbin
    }
}
<|endoftext|>


<commit_before><commit_msg>return WaitForResult::Failed if the socket is already closed<commit_after><|endoftext|>


<commit_before>// This is a part of Chrono.
// See README.md and LICENSE.txt for details.

use Timelike;
use std::ops::{Add, Sub};
use oldtime::Duration;

/// Extension trait for subsecond rounding or truncation to a maximum number
/// of digits. Rounding can be used to decrease the error variance when
/// serializing/persisting to lower precision. Truncation is the default
/// behavior in Chrono display formatting.  Either can be used to guarantee
/// equality (e.g. for testing) when round-tripping through a lower precision
/// format.
pub trait SubSecondRound {
    /// Return a copy rounded to the specified number of subsecond digits. With
    /// 9 or more digits, self is returned unmodified. Halfway values are
    /// rounded up (away from zero).
    fn round(self, digits: u16) -> Self;

    /// Return a copy truncated to the specified number of subsecond
    /// digits. With 9 or more digits, self is returned unmodified.
    fn trunc(self, digits: u16) -> Self;
}

impl<T> SubSecondRound for T
where T: Timelike + Add<Duration, Output=T> + Sub<Duration, Output=T>
{
    fn round(self, digits: u16) -> T {
        let span = span_for_digits(digits);
        let delta_down = self.nanosecond() % span;
        if delta_down > 0 {
            let delta_up = span - delta_down;
            if delta_up <= delta_down {
                self + Duration::nanoseconds(delta_up.into())
            } else {
                self - Duration::nanoseconds(delta_down.into())
            }
        } else {
            self // unchanged
        }
    }

    fn trunc(self, digits: u16) -> T {
        let span = span_for_digits(digits);
        let delta_down = self.nanosecond() % span;
        if delta_down > 0 {
            self - Duration::nanoseconds(delta_down.into())
        } else {
            self // unchanged
        }
    }
}

// Return the maximum span in nanoseconds for the target number of digits.
fn span_for_digits(digits: u16) -> u32 {
    // fast lookup form of: 10^(9-min(9,digits))
    match digits {
        0 => 1_000_000_000,
        1 =>   100_000_000,
        2 =>    10_000_000,
        3 =>     1_000_000,
        4 =>       100_000,
        5 =>        10_000,
        6 =>         1_000,
        7 =>           100,
        8 =>            10,
        _ =>             1
    }
}

#[cfg(test)]
mod tests {
    use Timelike;
    use offset::{FixedOffset, TimeZone, Utc};
    use super::SubSecondRound;

    #[test]
    fn test_round() {
        let pst = FixedOffset::east(8 * 60 * 60);
        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);

        assert_eq!(dt.round(10), dt);
        assert_eq!(dt.round(9), dt);
        assert_eq!(dt.round(8).nanosecond(), 084_660_680);
        assert_eq!(dt.round(7).nanosecond(), 084_660_700);
        assert_eq!(dt.round(6).nanosecond(), 084_661_000);
        assert_eq!(dt.round(5).nanosecond(), 084_660_000);
        assert_eq!(dt.round(4).nanosecond(), 084_700_000);
        assert_eq!(dt.round(3).nanosecond(), 085_000_000);
        assert_eq!(dt.round(2).nanosecond(), 080_000_000);
        assert_eq!(dt.round(1).nanosecond(), 100_000_000);

        assert_eq!(dt.round(0).nanosecond(), 0);
        assert_eq!(dt.round(0).second(), 13);

        let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
        assert_eq!(dt.round(9), dt);
        assert_eq!(dt.round(4), dt);
        assert_eq!(dt.round(3).nanosecond(), 751_000_000);
        assert_eq!(dt.round(2).nanosecond(), 750_000_000);
        assert_eq!(dt.round(1).nanosecond(), 800_000_000);

        assert_eq!(dt.round(0).nanosecond(), 0);
        assert_eq!(dt.round(0).second(), 28);
    }

    #[test]
    fn test_round_leap_nanos() {
        let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
        assert_eq!(dt.round(9), dt);
        assert_eq!(dt.round(4), dt);
        assert_eq!(dt.round(2).nanosecond(), 1_750_000_000);
        assert_eq!(dt.round(1).nanosecond(), 1_800_000_000);
        assert_eq!(dt.round(1).second(), 59);

        assert_eq!(dt.round(0).nanosecond(), 0);
        assert_eq!(dt.round(0).second(), 0);
    }

    #[test]
    fn test_trunc() {
        let pst = FixedOffset::east(8 * 60 * 60);
        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);

        assert_eq!(dt.trunc(10), dt);
        assert_eq!(dt.trunc(9), dt);
        assert_eq!(dt.trunc(8).nanosecond(), 084_660_680);
        assert_eq!(dt.trunc(7).nanosecond(), 084_660_600);
        assert_eq!(dt.trunc(6).nanosecond(), 084_660_000);
        assert_eq!(dt.trunc(5).nanosecond(), 084_660_000);
        assert_eq!(dt.trunc(4).nanosecond(), 084_600_000);
        assert_eq!(dt.trunc(3).nanosecond(), 084_000_000);
        assert_eq!(dt.trunc(2).nanosecond(), 080_000_000);
        assert_eq!(dt.trunc(1).nanosecond(), 0);

        assert_eq!(dt.trunc(0).nanosecond(), 0);
        assert_eq!(dt.trunc(0).second(), 13);

        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
        assert_eq!(dt.trunc(9), dt);
        assert_eq!(dt.trunc(4), dt);
        assert_eq!(dt.trunc(3).nanosecond(), 750_000_000);
        assert_eq!(dt.trunc(2).nanosecond(), 750_000_000);
        assert_eq!(dt.trunc(1).nanosecond(), 700_000_000);

        assert_eq!(dt.trunc(0).nanosecond(), 0);
        assert_eq!(dt.trunc(0).second(), 27);
    }

    #[test]
    fn test_trunc_leap_nanos() {
        let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
        assert_eq!(dt.trunc(9), dt);
        assert_eq!(dt.trunc(4), dt);
        assert_eq!(dt.trunc(2).nanosecond(), 1_750_000_000);
        assert_eq!(dt.trunc(1).nanosecond(), 1_700_000_000);
        assert_eq!(dt.trunc(1).second(), 59);

        assert_eq!(dt.trunc(0).nanosecond(), 1_000_000_000);
        assert_eq!(dt.trunc(0).second(), 59);
    }
}
<commit_msg>Rename to (round/trunc)_subsecs; add doc tests<commit_after>// This is a part of Chrono.
// See README.md and LICENSE.txt for details.

use Timelike;
use std::ops::{Add, Sub};
use oldtime::Duration;

/// Extension trait for subsecond rounding or truncation to a maximum number
/// of digits. Rounding can be used to decrease the error variance when
/// serializing/persisting to lower precision. Truncation is the default
/// behavior in Chrono display formatting.  Either can be used to guarantee
/// equality (e.g. for testing) when round-tripping through a lower precision
/// format.
pub trait SubSecondRound {
    /// Return a copy rounded to the specified number of subsecond digits. With
    /// 9 or more digits, self is returned unmodified. Halfway values are
    /// rounded up (away from zero).
    ///
    /// # Example
    /// ``` rust
    /// # use chrono::{DateTime, SubSecondRound, Timelike, TimeZone, Utc};
    /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
    /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000);
    /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000);
    /// ```
    fn round_subsecs(self, digits: u16) -> Self;

    /// Return a copy truncated to the specified number of subsecond
    /// digits. With 9 or more digits, self is returned unmodified.
    ///
    /// # Example
    /// ``` rust
    /// # use chrono::{DateTime, SubSecondRound, Timelike, TimeZone, Utc};
    /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154);
    /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000);
    /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000);
    /// ```
    fn trunc_subsecs(self, digits: u16) -> Self;
}

impl<T> SubSecondRound for T
where T: Timelike + Add<Duration, Output=T> + Sub<Duration, Output=T>
{
    fn round_subsecs(self, digits: u16) -> T {
        let span = span_for_digits(digits);
        let delta_down = self.nanosecond() % span;
        if delta_down > 0 {
            let delta_up = span - delta_down;
            if delta_up <= delta_down {
                self + Duration::nanoseconds(delta_up.into())
            } else {
                self - Duration::nanoseconds(delta_down.into())
            }
        } else {
            self // unchanged
        }
    }

    fn trunc_subsecs(self, digits: u16) -> T {
        let span = span_for_digits(digits);
        let delta_down = self.nanosecond() % span;
        if delta_down > 0 {
            self - Duration::nanoseconds(delta_down.into())
        } else {
            self // unchanged
        }
    }
}

// Return the maximum span in nanoseconds for the target number of digits.
fn span_for_digits(digits: u16) -> u32 {
    // fast lookup form of: 10^(9-min(9,digits))
    match digits {
        0 => 1_000_000_000,
        1 =>   100_000_000,
        2 =>    10_000_000,
        3 =>     1_000_000,
        4 =>       100_000,
        5 =>        10_000,
        6 =>         1_000,
        7 =>           100,
        8 =>            10,
        _ =>             1
    }
}

#[cfg(test)]
mod tests {
    use Timelike;
    use offset::{FixedOffset, TimeZone, Utc};
    use super::SubSecondRound;

    #[test]
    fn test_round() {
        let pst = FixedOffset::east(8 * 60 * 60);
        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);

        assert_eq!(dt.round_subsecs(10), dt);
        assert_eq!(dt.round_subsecs(9), dt);
        assert_eq!(dt.round_subsecs(8).nanosecond(), 084_660_680);
        assert_eq!(dt.round_subsecs(7).nanosecond(), 084_660_700);
        assert_eq!(dt.round_subsecs(6).nanosecond(), 084_661_000);
        assert_eq!(dt.round_subsecs(5).nanosecond(), 084_660_000);
        assert_eq!(dt.round_subsecs(4).nanosecond(), 084_700_000);
        assert_eq!(dt.round_subsecs(3).nanosecond(), 085_000_000);
        assert_eq!(dt.round_subsecs(2).nanosecond(), 080_000_000);
        assert_eq!(dt.round_subsecs(1).nanosecond(), 100_000_000);

        assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
        assert_eq!(dt.round_subsecs(0).second(), 13);

        let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
        assert_eq!(dt.round_subsecs(9), dt);
        assert_eq!(dt.round_subsecs(4), dt);
        assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000);
        assert_eq!(dt.round_subsecs(2).nanosecond(), 750_000_000);
        assert_eq!(dt.round_subsecs(1).nanosecond(), 800_000_000);

        assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
        assert_eq!(dt.round_subsecs(0).second(), 28);
    }

    #[test]
    fn test_round_leap_nanos() {
        let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
        assert_eq!(dt.round_subsecs(9), dt);
        assert_eq!(dt.round_subsecs(4), dt);
        assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000);
        assert_eq!(dt.round_subsecs(1).nanosecond(), 1_800_000_000);
        assert_eq!(dt.round_subsecs(1).second(), 59);

        assert_eq!(dt.round_subsecs(0).nanosecond(), 0);
        assert_eq!(dt.round_subsecs(0).second(), 0);
    }

    #[test]
    fn test_trunc() {
        let pst = FixedOffset::east(8 * 60 * 60);
        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684);

        assert_eq!(dt.trunc_subsecs(10), dt);
        assert_eq!(dt.trunc_subsecs(9), dt);
        assert_eq!(dt.trunc_subsecs(8).nanosecond(), 084_660_680);
        assert_eq!(dt.trunc_subsecs(7).nanosecond(), 084_660_600);
        assert_eq!(dt.trunc_subsecs(6).nanosecond(), 084_660_000);
        assert_eq!(dt.trunc_subsecs(5).nanosecond(), 084_660_000);
        assert_eq!(dt.trunc_subsecs(4).nanosecond(), 084_600_000);
        assert_eq!(dt.trunc_subsecs(3).nanosecond(), 084_000_000);
        assert_eq!(dt.trunc_subsecs(2).nanosecond(), 080_000_000);
        assert_eq!(dt.trunc_subsecs(1).nanosecond(), 0);

        assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
        assert_eq!(dt.trunc_subsecs(0).second(), 13);

        let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000);
        assert_eq!(dt.trunc_subsecs(9), dt);
        assert_eq!(dt.trunc_subsecs(4), dt);
        assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000);
        assert_eq!(dt.trunc_subsecs(2).nanosecond(), 750_000_000);
        assert_eq!(dt.trunc_subsecs(1).nanosecond(), 700_000_000);

        assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0);
        assert_eq!(dt.trunc_subsecs(0).second(), 27);
    }

    #[test]
    fn test_trunc_leap_nanos() {
        let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000);
        assert_eq!(dt.trunc_subsecs(9), dt);
        assert_eq!(dt.trunc_subsecs(4), dt);
        assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000);
        assert_eq!(dt.trunc_subsecs(1).nanosecond(), 1_700_000_000);
        assert_eq!(dt.trunc_subsecs(1).second(), 59);

        assert_eq!(dt.trunc_subsecs(0).nanosecond(), 1_000_000_000);
        assert_eq!(dt.trunc_subsecs(0).second(), 59);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

fn process_anagram_case(word: &str, inputs: &[&str], expected: &[&str]) {
    let result = anagram::anagrams_for(word, inputs);

    let expected: HashSet<&str> = expected.iter().cloned().collect();

    assert_eq!(result, expected);
}

#[test]
fn test_no_matches() {
    let word = "diaper";

    let inputs = ["hello", "world", "zombies", "pants"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_detect_simple_anagram() {
    let word = "ant";

    let inputs = ["tan", "stand", "at"];

    let outputs = vec!["tan"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_confuse_different_duplicates() {
    let word = "galea";

    let inputs = ["eagle"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_eliminate_anagram_subsets() {
    let word = "good";

    let inputs = ["dog", "goody"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_detect_anagram() {
    let word = "listen";

    let inputs = ["enlists", "google", "inlets", "banana"];

    let outputs = vec!["inlets"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_multiple_anagrams() {
    let word = "allergy";

    let inputs = [
        "gallery",
        "ballerina",
        "regally",
        "clergy",
        "largely",
        "leading",
    ];

    let outputs = vec!["gallery", "regally", "largely"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_case_insensitive_anagrams() {
    let word = "Orchestra";

    let inputs = ["cashregister", "Carthorse", "radishes"];

    let outputs = vec!["Carthorse"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_unicode_anagrams() {
    let word = "ΑΒΓ";

    // These words don't make sense, they're just greek letters cobbled together.
    let inputs = ["ΒΓΑ", "ΒΓΔ", "γβα"];

    let outputs = vec!["ΒΓΑ", "γβα"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_misleading_unicode_anagrams() {
    // Despite what a human might think these words different letters, the input uses Greek A and B
    // while the list of potential anagrams uses Latin A and B.
    let word = "ΑΒΓ";

    let inputs = ["ABΓ"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_word_as_its_own_anagram() {
    let word = "banana";

    let inputs = ["banana"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_differently_cased_word_as_its_own_anagram() {
    let word = "banana";

    let inputs = ["bAnana"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_differently_cased_unicode_word_as_its_own_anagram() {
    let word = "ΑΒΓ";

    let inputs = ["ΑΒγ"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_same_bytes_different_chars() {
    let word = "a⬂"; // 61 E2 AC 82

    let inputs = ["€a"]; // E2 82 AC 61

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}
<commit_msg>Add test case to rust/anagram to prevent ascii-sum-solutions<commit_after>use std::collections::HashSet;

fn process_anagram_case(word: &str, inputs: &[&str], expected: &[&str]) {
    let result = anagram::anagrams_for(word, inputs);

    let expected: HashSet<&str> = expected.iter().cloned().collect();

    assert_eq!(result, expected);
}

#[test]
fn test_no_matches() {
    let word = "diaper";

    let inputs = ["hello", "world", "zombies", "pants"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_detect_simple_anagram() {
    let word = "ant";

    let inputs = ["tan", "stand", "at"];

    let outputs = vec!["tan"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_confuse_different_duplicates() {
    let word = "galea";

    let inputs = ["eagle"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_eliminate_anagram_subsets() {
    let word = "good";

    let inputs = ["dog", "goody"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_detect_anagram() {
    let word = "listen";

    let inputs = ["enlists", "google", "inlets", "banana"];

    let outputs = vec!["inlets"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_multiple_anagrams() {
    let word = "allergy";

    let inputs = [
        "gallery",
        "ballerina",
        "regally",
        "clergy",
        "largely",
        "leading",
    ];

    let outputs = vec!["gallery", "regally", "largely"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_case_insensitive_anagrams() {
    let word = "Orchestra";

    let inputs = ["cashregister", "Carthorse", "radishes"];

    let outputs = vec!["Carthorse"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_unicode_anagrams() {
    let word = "ΑΒΓ";

    // These words don't make sense, they're just greek letters cobbled together.
    let inputs = ["ΒΓΑ", "ΒΓΔ", "γβα"];

    let outputs = vec!["ΒΓΑ", "γβα"];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_misleading_unicode_anagrams() {
    // Despite what a human might think these words different letters, the input uses Greek A and B
    // while the list of potential anagrams uses Latin A and B.
    let word = "ΑΒΓ";

    let inputs = ["ABΓ"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_word_as_its_own_anagram() {
    let word = "banana";

    let inputs = ["banana"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_differently_cased_word_as_its_own_anagram() {
    let word = "banana";

    let inputs = ["bAnana"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_does_not_detect_a_differently_cased_unicode_word_as_its_own_anagram() {
    let word = "ΑΒΓ";

    let inputs = ["ΑΒγ"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_same_bytes_different_chars() {
    let word = "a⬂"; // 61 E2 AC 82

    let inputs = ["€a"]; // E2 82 AC 61

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}

#[test]
#[ignore]
fn test_different_words_but_same_ascii_sum() {
    let word = "bc";

    let inputs = ["ad"];

    let outputs = vec![];

    process_anagram_case(word, &inputs, &outputs);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;

use model::Model;
use resource::ResourceManager;
use transform::Transform;

pub type Id = u32;

pub struct Scene<'a> {
  /// Resource manager.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
}

pub struct Object {
  model_id: Id,
  transform: Transform
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
    }
  }

  pub fn get_id<T>(&mut self, inst_name: &str) -> Option<Id> where T: GetId {
    T::get_id(self, inst_name)
  }

  pub fn resource_manager(&mut self) -> &mut ResourceManager {
    &mut self.res_manager
  }
}

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id> {
    match scene.model_cache.get(inst_name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", inst_name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(inst_name.to_owned(), model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", inst_name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", inst_name);
          None
        }
      }
    }
  }
}
<commit_msg>Removed useless stuff.<commit_after>use std::collections::HashMap;
use std::path::Path;

use model::Model;
use entity::Entity;
use resource::ResourceManager;
use transform::Transform;

pub type Id = u32;

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Resource manager; used to handle scarce resources.
  res_manager: ResourceManager,
  /// List of all models used in the scene.
  models: Vec<Model<'a>>,
  /// Model cache used to resolve Id based on instance name.
  model_cache: HashMap<String, Id>,
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      res_manager: ResourceManager::new(root),
      models: Vec::new(),
      model_cache: HashMap::new(),
    }
  }

  pub fn get_id<T>(&mut self, inst_name: &str) -> Option<Id> where T: GetId {
    T::get_id(self, inst_name)
  }

  pub fn resource_manager(&mut self) -> &mut ResourceManager {
    &mut self.res_manager
  }
}

pub trait GetId {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id>;
}

impl<'b> GetId for Model<'b> {
  fn get_id<'a>(scene: &mut Scene<'a>, inst_name: &str) -> Option<Id> {
    match scene.model_cache.get(inst_name).cloned() {
      id@Some(..) => id,
      None => {
        // cache miss; load then
        let path_str = format!("data/models/{}.obj", inst_name);
        let path = Path::new(&path_str);

        if path.exists() {
          match Model::load(&mut scene.res_manager, path) {
            Ok(model) => {
              let model_id = scene.models.len() as u32;

              // add the model to the list of loaded models
              scene.models.push(model);
              // add the model to the cache
              scene.model_cache.insert(inst_name.to_owned(), model_id);

              Some(model_id)
            },
            Err(e) => {
              err!("unable to load model '{}': '{:?}'", inst_name, e);
              None
            }
          }
        } else { // TODO: add a manifest override to look in somewhere else
          err!("model '{}' cannot be found", inst_name);
          None
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>
use ggez;
use ggez::GameResult;
use ggez::conf;
use ggez::event;
use ggez::game::GameState;

use std::collections::BTreeMap;
use std::time::Duration;

pub trait SavedScene<T> {
    fn load(&self) -> Box<Scene<T>>;
    fn name(&self) -> &str;
}

pub trait Scene<T> {
    fn unload(&mut self) -> Box<SavedScene<T>>;

    /// Called upon each physics update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self,
              ctx: &mut ggez::Context,
              dt: Duration,
              scenes: &mut SceneStore<T>)
              -> GameResult<Option<String>>;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::sleep_until_next_frame()`
    fn draw(&mut self, ctx: &mut ggez::Context, scenes: &mut SceneStore<T>) -> GameResult<()>;

    // You don't have to override these if you don't want to; the defaults
    // do nothing.
    // It might be nice to be able to have custom event types and a map or
    // such of handlers?  Hmm, maybe later.
    fn mouse_button_down_event(&mut self, _button: event::Mouse, _x: i32, _y: i32) {}

    fn mouse_button_up_event(&mut self, _button: event::Mouse, _x: i32, _y: i32) {}

    fn mouse_motion_event(&mut self,
                          _state: event::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {}

    fn key_down_event(&mut self,
                      _keycode: Option<event::Keycode>,
                      _keymod: event::Mod,
                      _repeat: bool) {
    }

    fn key_up_event(&mut self,
                    _keycode: Option<event::Keycode>,
                    _keymod: event::Mod,
                    _repeat: bool) {
    }

    fn focus_event(&mut self, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        println!("Quitting game");
        false
    }
}

/// The GameData trait just provides
/// a method to create a new object of type T, instantiating
/// your global game data.
///
/// It also provides a method that is called to generate
/// the first scene of your game.
pub trait GameData<T>
    where Self: Sized
{
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self>;
    fn starting_scene() -> Box<SavedScene<T>>;
}

pub struct SceneStore<T> {
    states: BTreeMap<String, Box<SavedScene<T>>>,
    pub game_data: T,
}

impl<T> SceneStore<T> {
    pub fn add<S: SavedScene<T> + 'static>(&mut self, scene_state: S) {
        self.states.insert(scene_state.name().to_string(), Box::new(scene_state));
    }
}

/// A SceneManager is a GameState that handles Scene's
/// and switches from one to another when requested.
///
/// The stuff you would normally store in your GameState
/// type should implement GameData and go into the T type.
pub struct SceneManager<T> {
    store: SceneStore<T>,
    current: Box<Scene<T>>,
    next_scene: Option<String>,
}

impl<T> GameState for SceneManager<T>
    where T: GameData<T>
{
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self> {
        let starting_scene_state = T::starting_scene();
        let game_data = T::load(ctx, conf)?;

        Ok(Self::new(starting_scene_state, game_data))
    }

    fn update(&mut self, ctx: &mut ggez::Context, dt: Duration) -> GameResult<()> {
        // TODO: Get rid of this hacky clone!
        if let Some(ref scene_name) = self.next_scene.clone() {
            self.switch_scene(&scene_name)?;
        }
        self.next_scene = self.current.update(ctx, dt, &mut self.store)?;
        Ok(())
    }

    fn draw(&mut self, ctx: &mut ggez::Context) -> GameResult<()> {
        self.current.draw(ctx, &mut self.store)
    }

    fn mouse_button_down_event(&mut self, button: event::Mouse, x: i32, y: i32) {
        self.current.mouse_button_down_event(button, x, y)
    }

    fn mouse_button_up_event(&mut self, button: event::Mouse, x: i32, y: i32) {
        self.current.mouse_button_up_event(button, x, y)
    }

    fn mouse_motion_event(&mut self,
                          _state: event::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
        self.current.mouse_motion_event(_state, _x, _y, _xrel, _yrel)
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {
        self.current.mouse_wheel_event(_x, _y)
    }

    fn key_down_event(&mut self,
                      _keycode: Option<event::Keycode>,
                      _keymod: event::Mod,
                      _repeat: bool) {
        self.current.key_down_event(_keycode, _keymod, _repeat)
    }

    fn key_up_event(&mut self,
                    _keycode: Option<event::Keycode>,
                    _keymod: event::Mod,
                    _repeat: bool) {
        self.current.key_up_event(_keycode, _keymod, _repeat)
    }

    fn focus_event(&mut self, _gained: bool) {
        self.current.focus_event(_gained)
    }

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        self.current.quit_event()
    }
}

impl<T> SceneManager<T> {
    /// This lets us create a SceneManager by providing the data for it,
    /// instead of having it implicitly created via the GameData trait.
    fn new(starting_scene_state: Box<SavedScene<T>>, game_data: T) -> Self {
        let starting_scene = starting_scene_state.load();
        let mut scenes: BTreeMap<String, Box<SavedScene<T>>> = BTreeMap::new();
        scenes.insert(starting_scene_state.name().to_string(),
                      starting_scene_state);
        let store = SceneStore {
            states: scenes,

            game_data: game_data,
        };
        let sm = SceneManager {
            current: starting_scene,
            store: store,
            next_scene: None,
        };
        sm
    }

    pub fn current(&self) -> &Scene<T> {
        &*self.current
    }

    pub fn current_mut(&mut self) -> &mut Scene<T> {
        &mut *self.current
    }

    pub fn switch_scene(&mut self, scene_name: &str) -> GameResult<()> {
        // Save current scene
        let old_scene_state = self.current.unload();
        let old_scene_name = old_scene_state.name().to_string();
        self.store.states.insert(old_scene_name, old_scene_state);
        // Then load the new one.
        if let Some(scene_state) = self.store.states.get_mut(scene_name) {
            let new_scene = scene_state.load();
            self.current = new_scene;
            Ok(())
        } else {
            let msg = format!("SceneManager: Asked to load scene {} but it did not exist?",
                              scene_name);
            Err(ggez::GameError::ResourceNotFound(msg))
        }
    }
}

#[cfg(test)]
mod tests {

    use ggez;
    use ggez::GameResult;
    use ggez::game::GameState;

    use std::time::Duration;

    use super::{Scene, SavedScene, SceneManager, SceneStore};

    #[derive(Clone, Debug)]
    struct TestSavedScene {
        value: i32,
        name: String,
    }

    impl SavedScene<()> for TestSavedScene {
        fn load(&self) -> Box<Scene<()>> {
            Box::new(TestScene(self.clone()))
        }
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[derive(Clone, Debug)]
    struct TestScene(TestSavedScene);

    impl Scene<()> for TestScene {
        fn unload(&mut self) -> Box<SavedScene<()>> {
            Box::new(self.0.clone())
        }

        fn update(&mut self,
                  _ctx: &mut ggez::Context,
                  _dt: Duration,
                  _scenes: &mut SceneStore<()>)
                  -> GameResult<Option<String>> {
            Ok(None)
        }

        fn draw(&mut self,
                _ctx: &mut ggez::Context,
                _scenes: &mut SceneStore<()>)
                -> GameResult<()> {
            Ok(())
        }
    }

    #[test]
    fn test_scene_switching() {
        let default_scene = TestSavedScene {
            name: "default scene".to_string(),
            value: 42,
        };
        let new_scene = TestSavedScene {
            name: "other scene".to_string(),
            value: 23,
        };
        let mut sm = SceneManager::new(Box::new(default_scene), ());
        sm.store.add(new_scene);

        {
            let s = sm.current_mut().unload();
            assert_eq!(s.name(), "default scene");
        }
        let res = sm.switch_scene("other scene");
        assert!(res.is_ok());

        {
            let s = sm.current_mut().unload();
            assert_eq!(s.name(), "other scene");
        }

        let res = sm.switch_scene("non existent scene");
        assert!(res.is_err());
    }

}
<commit_msg>rust sdl2 0.27.2<commit_after>
use ggez;
use ggez::GameResult;
use ggez::conf;
use ggez::event;
use ggez::game::GameState;

use std::collections::BTreeMap;
use std::time::Duration;

pub trait SavedScene<T> {
    fn load(&self) -> Box<Scene<T>>;
    fn name(&self) -> &str;
}

pub trait Scene<T> {
    fn unload(&mut self) -> Box<SavedScene<T>>;

    /// Called upon each physics update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self,
              ctx: &mut ggez::Context,
              dt: Duration,
              scenes: &mut SceneStore<T>)
              -> GameResult<Option<String>>;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// `graphics::clear()` and end it with
    /// `graphics::present()` and `timer::sleep_until_next_frame()`
    fn draw(&mut self, ctx: &mut ggez::Context, scenes: &mut SceneStore<T>) -> GameResult<()>;

    // You don't have to override these if you don't want to; the defaults
    // do nothing.
    // It might be nice to be able to have custom event types and a map or
    // such of handlers?  Hmm, maybe later.
    fn mouse_button_down_event(&mut self, _button: event::MouseButton, _x: i32, _y: i32) {}

    fn mouse_button_up_event(&mut self, _button: event::MouseButton, _x: i32, _y: i32) {}

    fn mouse_motion_event(&mut self,
                          _state: event::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {}

    fn key_down_event(&mut self,
                      _keycode: Option<event::Keycode>,
                      _keymod: event::Mod,
                      _repeat: bool) {
    }

    fn key_up_event(&mut self,
                    _keycode: Option<event::Keycode>,
                    _keymod: event::Mod,
                    _repeat: bool) {
    }

    fn focus_event(&mut self, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        println!("Quitting game");
        false
    }
}

/// The GameData trait just provides
/// a method to create a new object of type T, instantiating
/// your global game data.
///
/// It also provides a method that is called to generate
/// the first scene of your game.
pub trait GameData<T>
    where Self: Sized
{
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self>;
    fn starting_scene() -> Box<SavedScene<T>>;
}

pub struct SceneStore<T> {
    states: BTreeMap<String, Box<SavedScene<T>>>,
    pub game_data: T,
}

impl<T> SceneStore<T> {
    pub fn add<S: SavedScene<T> + 'static>(&mut self, scene_state: S) {
        self.states.insert(scene_state.name().to_string(), Box::new(scene_state));
    }
}

/// A SceneManager is a GameState that handles Scene's
/// and switches from one to another when requested.
///
/// The stuff you would normally store in your GameState
/// type should implement GameData and go into the T type.
pub struct SceneManager<T> {
    store: SceneStore<T>,
    current: Box<Scene<T>>,
    next_scene: Option<String>,
}

impl<T> GameState for SceneManager<T>
    where T: GameData<T>
{
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self> {
        let starting_scene_state = T::starting_scene();
        let game_data = T::load(ctx, conf)?;

        Ok(Self::new(starting_scene_state, game_data))
    }

    fn update(&mut self, ctx: &mut ggez::Context, dt: Duration) -> GameResult<()> {
        // TODO: Get rid of this hacky clone!
        if let Some(ref scene_name) = self.next_scene.clone() {
            self.switch_scene(&scene_name)?;
        }
        self.next_scene = self.current.update(ctx, dt, &mut self.store)?;
        Ok(())
    }

    fn draw(&mut self, ctx: &mut ggez::Context) -> GameResult<()> {
        self.current.draw(ctx, &mut self.store)
    }

    fn mouse_button_down_event(&mut self, button: event::MouseButton, x: i32, y: i32) {
        self.current.mouse_button_down_event(button, x, y)
    }

    fn mouse_button_up_event(&mut self, button: event::MouseButton, x: i32, y: i32) {
        self.current.mouse_button_up_event(button, x, y)
    }

    fn mouse_motion_event(&mut self,
                          _state: event::MouseState,
                          _x: i32,
                          _y: i32,
                          _xrel: i32,
                          _yrel: i32) {
        self.current.mouse_motion_event(_state, _x, _y, _xrel, _yrel)
    }

    fn mouse_wheel_event(&mut self, _x: i32, _y: i32) {
        self.current.mouse_wheel_event(_x, _y)
    }

    fn key_down_event(&mut self,
                      _keycode: Option<event::Keycode>,
                      _keymod: event::Mod,
                      _repeat: bool) {
        self.current.key_down_event(_keycode, _keymod, _repeat)
    }

    fn key_up_event(&mut self,
                    _keycode: Option<event::Keycode>,
                    _keymod: event::Mod,
                    _repeat: bool) {
        self.current.key_up_event(_keycode, _keymod, _repeat)
    }

    fn focus_event(&mut self, _gained: bool) {
        self.current.focus_event(_gained)
    }

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit.
    fn quit_event(&mut self) -> bool {
        self.current.quit_event()
    }
}

impl<T> SceneManager<T> {
    /// This lets us create a SceneManager by providing the data for it,
    /// instead of having it implicitly created via the GameData trait.
    fn new(starting_scene_state: Box<SavedScene<T>>, game_data: T) -> Self {
        let starting_scene = starting_scene_state.load();
        let mut scenes: BTreeMap<String, Box<SavedScene<T>>> = BTreeMap::new();
        scenes.insert(starting_scene_state.name().to_string(),
                      starting_scene_state);
        let store = SceneStore {
            states: scenes,

            game_data: game_data,
        };
        let sm = SceneManager {
            current: starting_scene,
            store: store,
            next_scene: None,
        };
        sm
    }

    pub fn current(&self) -> &Scene<T> {
        &*self.current
    }

    pub fn current_mut(&mut self) -> &mut Scene<T> {
        &mut *self.current
    }

    pub fn switch_scene(&mut self, scene_name: &str) -> GameResult<()> {
        // Save current scene
        let old_scene_state = self.current.unload();
        let old_scene_name = old_scene_state.name().to_string();
        self.store.states.insert(old_scene_name, old_scene_state);
        // Then load the new one.
        if let Some(scene_state) = self.store.states.get_mut(scene_name) {
            let new_scene = scene_state.load();
            self.current = new_scene;
            Ok(())
        } else {
            let msg = format!("SceneManager: Asked to load scene {} but it did not exist?",
                              scene_name);
            Err(ggez::GameError::ResourceNotFound(msg))
        }
    }
}

#[cfg(test)]
mod tests {

    use ggez;
    use ggez::GameResult;
    use ggez::game::GameState;

    use std::time::Duration;

    use super::{Scene, SavedScene, SceneManager, SceneStore};

    #[derive(Clone, Debug)]
    struct TestSavedScene {
        value: i32,
        name: String,
    }

    impl SavedScene<()> for TestSavedScene {
        fn load(&self) -> Box<Scene<()>> {
            Box::new(TestScene(self.clone()))
        }
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[derive(Clone, Debug)]
    struct TestScene(TestSavedScene);

    impl Scene<()> for TestScene {
        fn unload(&mut self) -> Box<SavedScene<()>> {
            Box::new(self.0.clone())
        }

        fn update(&mut self,
                  _ctx: &mut ggez::Context,
                  _dt: Duration,
                  _scenes: &mut SceneStore<()>)
                  -> GameResult<Option<String>> {
            Ok(None)
        }

        fn draw(&mut self,
                _ctx: &mut ggez::Context,
                _scenes: &mut SceneStore<()>)
                -> GameResult<()> {
            Ok(())
        }
    }

    #[test]
    fn test_scene_switching() {
        let default_scene = TestSavedScene {
            name: "default scene".to_string(),
            value: 42,
        };
        let new_scene = TestSavedScene {
            name: "other scene".to_string(),
            value: 23,
        };
        let mut sm = SceneManager::new(Box::new(default_scene), ());
        sm.store.add(new_scene);

        {
            let s = sm.current_mut().unload();
            assert_eq!(s.name(), "default scene");
        }
        let res = sm.switch_scene("other scene");
        assert!(res.is_ok());

        {
            let s = sm.current_mut().unload();
            assert_eq!(s.name(), "other scene");
        }

        let res = sm.switch_scene("non existent scene");
        assert!(res.is_err());
    }

}
<|endoftext|>