<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter;
use buffer::Buffer;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::DescriptorSetDesc;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use image::Image;

/// A collection of descriptor set objects.
pub unsafe trait DescriptorSetsCollection {
    /// Returns the number of sets in the collection. Includes possibly empty sets.
    ///
    /// In other words, this should be equal to the highest set number plus one.
    fn num_sets(&self) -> usize;

    /// Returns the descriptor set with the given id. Returns `None` if the set is empty.
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet>;

    /// Returns the number of descriptors in the set. Includes possibly empty descriptors.
    ///
    /// Returns `None` if the set is out of range.
    fn num_bindings_in_set(&self, set: usize) -> Option<usize>;

    /// Returns the descriptor for the given binding of the given set.
    ///
    /// Returns `None` if out of range.
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc>;

    /// Returns the list of buffers used by this descriptor set. Includes buffer views.
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a>;

    /// Returns the list of images used by this descriptor set. Includes image views.
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a>;
}

unsafe impl DescriptorSetsCollection for () {
    #[inline]
    fn num_sets(&self) -> usize {
        0
    }

    #[inline]
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet> {
        None
    }

    #[inline]
    fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
        None
    }

    #[inline]
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
        None
    }

    #[inline]
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
        Box::new(iter::empty())
    }

    #[inline]
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
        Box::new(iter::empty())
    }
}

unsafe impl<T> DescriptorSetsCollection for T
    where T: DescriptorSet
{
    #[inline]
    fn num_sets(&self) -> usize {
        1
    }

    #[inline]
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet> {
        match set {
            0 => Some(self.inner()),
            _ => None
        }
    }

    #[inline]
    fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
        match set {
            0 => Some(self.num_bindings()),
            _ => None
        }
    }

    #[inline]
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
        match set {
            0 => self.descriptor(binding),
            _ => None
        }
    }

    #[inline]
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
        DescriptorSet::buffers_list(self)
    }

    #[inline]
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
        DescriptorSet::images_list(self)
    }
}

macro_rules! impl_collection {
    ($first:ident $(, $others:ident)*) => (
        unsafe impl<$first$(, $others)*> DescriptorSetsCollection for ($first, $($others),*)
            where $first: DescriptorSet + DescriptorSetDesc
                  $(, $others: DescriptorSet + DescriptorSetDesc)*
        {
            #[inline]
            fn num_sets(&self) -> usize {
                #![allow(non_snake_case)]
                1 $( + {let $others=0;1})*
            }

            #[inline]
            fn descriptor_set(&self, mut set: usize) -> Option<&UnsafeDescriptorSet> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return Some(self.0.inner());
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return Some($others.inner());
                    }
                )*

                None
            }

            #[inline]
            fn num_bindings_in_set(&self, mut set: usize) -> Option<usize> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return Some(self.0.num_bindings());
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return Some($others.num_bindings());
                    }
                )*

                None
            }

            #[inline]
            fn descriptor(&self, mut set: usize, binding: usize) -> Option<DescriptorDesc> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return self.0.descriptor(binding);
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return $others.descriptor(binding);
                    }
                )*

                None
            }

            #[inline]
            fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
                let &(ref first, $(ref $others,)*) = self;
                let mut output = Vec::new();
                output.extend(first.buffers_list());
                $(
                    output.extend($others.buffers_list());
                )*
                Box::new(output.into_iter())
            }

            #[inline]
            fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
                let &(ref first, $(ref $others,)*) = self;
                let mut output = Vec::new();
                output.extend(first.images_list());
                $(
                    output.extend($others.images_list());
                )*
                Box::new(output.into_iter())
            }
        }

        impl_collection!($($others),*);
    );

    () => ();
}

impl_collection!(Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
<commit_msg>Fix tons of warnings<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::iter;
use buffer::Buffer;
use descriptor::descriptor::DescriptorDesc;
use descriptor::descriptor_set::DescriptorSet;
use descriptor::descriptor_set::DescriptorSetDesc;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use image::Image;

/// A collection of descriptor set objects.
pub unsafe trait DescriptorSetsCollection {
    /// Returns the number of sets in the collection. Includes possibly empty sets.
    ///
    /// In other words, this should be equal to the highest set number plus one.
    fn num_sets(&self) -> usize;

    /// Returns the descriptor set with the given id. Returns `None` if the set is empty.
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet>;

    /// Returns the number of descriptors in the set. Includes possibly empty descriptors.
    ///
    /// Returns `None` if the set is out of range.
    fn num_bindings_in_set(&self, set: usize) -> Option<usize>;

    /// Returns the descriptor for the given binding of the given set.
    ///
    /// Returns `None` if out of range.
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc>;

    /// Returns the list of buffers used by this descriptor set. Includes buffer views.
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a>;

    /// Returns the list of images used by this descriptor set. Includes image views.
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a>;
}

unsafe impl DescriptorSetsCollection for () {
    #[inline]
    fn num_sets(&self) -> usize {
        0
    }

    #[inline]
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet> {
        None
    }

    #[inline]
    fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
        None
    }

    #[inline]
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
        None
    }

    #[inline]
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
        Box::new(iter::empty())
    }

    #[inline]
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
        Box::new(iter::empty())
    }
}

unsafe impl<T> DescriptorSetsCollection for T
    where T: DescriptorSet
{
    #[inline]
    fn num_sets(&self) -> usize {
        1
    }

    #[inline]
    fn descriptor_set(&self, set: usize) -> Option<&UnsafeDescriptorSet> {
        match set {
            0 => Some(self.inner()),
            _ => None
        }
    }

    #[inline]
    fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
        match set {
            0 => Some(self.num_bindings()),
            _ => None
        }
    }

    #[inline]
    fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
        match set {
            0 => self.descriptor(binding),
            _ => None
        }
    }

    #[inline]
    fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
        DescriptorSet::buffers_list(self)
    }

    #[inline]
    fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
        DescriptorSet::images_list(self)
    }
}

macro_rules! impl_collection {
    ($first:ident $(, $others:ident)*) => (
        unsafe impl<$first$(, $others)*> DescriptorSetsCollection for ($first, $($others),*)
            where $first: DescriptorSet + DescriptorSetDesc
                  $(, $others: DescriptorSet + DescriptorSetDesc)*
        {
            #[inline]
            fn num_sets(&self) -> usize {
                #![allow(non_snake_case)]
                1 $( + {let $others=0;1})*
            }

            #[inline]
            fn descriptor_set(&self, mut set: usize) -> Option<&UnsafeDescriptorSet> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return Some(self.0.inner());
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return Some($others.inner());
                    }
                )*

                None
            }

            #[inline]
            fn num_bindings_in_set(&self, mut set: usize) -> Option<usize> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return Some(self.0.num_bindings());
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return Some($others.num_bindings());
                    }
                )*

                None
            }

            #[inline]
            fn descriptor(&self, mut set: usize, binding: usize) -> Option<DescriptorDesc> {
                #![allow(non_snake_case)]
                #![allow(unused_mut)]       // For the `set` parameter.

                if set == 0 {
                    return self.0.descriptor(binding);
                }

                let &(_, $(ref $others,)*) = self;

                $(
                    set -= 1;
                    if set == 0 {
                        return $others.descriptor(binding);
                    }
                )*

                None
            }

            #[inline]
            fn buffers_list<'a>(&'a self) -> Box<Iterator<Item = &'a Buffer> + 'a> {
                #![allow(non_snake_case)]

                let &(ref first, $(ref $others,)*) = self;
                let mut output = Vec::new();
                output.extend(first.buffers_list());
                $(
                    output.extend($others.buffers_list());
                )*
                Box::new(output.into_iter())
            }

            #[inline]
            fn images_list<'a>(&'a self) -> Box<Iterator<Item = &'a Image> + 'a> {
                #![allow(non_snake_case)]

                let &(ref first, $(ref $others,)*) = self;
                let mut output = Vec::new();
                output.extend(first.images_list());
                $(
                    output.extend($others.images_list());
                )*
                Box::new(output.into_iter())
            }
        }

        impl_collection!($($others),*);
    );

    () => ();
}

impl_collection!(Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
<|endoftext|>


<commit_before>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::SolutionRankDist;
use selection::select_solutions;
use std::iter::FromIterator;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals.
    pub fn rate<F, E>(self, eval: &E) -> RatedPopulation<I, F>
        where F: MultiObjective + Clone,
              E: Fn(&I) -> F
    {
        let fitness = self.individuals.iter().map(eval).collect();
        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }

    /// Rate the individuals in parallel.
    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> SelectedPopulation<I, F>
        where D: Domination<F>
    {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness,
                                         population_size,
                                         num_objectives,
                                         domination);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    /// Generate an offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: Fn(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> SelectedPopulation<I, F> {
        SelectedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
            rank_dist: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        self.all(&mut |ind, fit| {
            // XXX: Optimize. Avoid clone
            new_ind.push(ind.clone());
            new_fit.push(fit.clone());
        });

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
        }
    }

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f32)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.rank_dist.iter().map(|rd| rd.rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}
<commit_msg>Remove sequential rating<commit_after>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::SolutionRankDist;
use selection::select_solutions;
use std::iter::FromIterator;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;

/// An unrated Population of individuals.
pub struct UnratedPopulation<I>
    where I: Clone
{
    individuals: Vec<I>,
}

/// A rated Population of individuals, i.e.
/// each individual has a fitness assigned.
pub struct RatedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
}

/// A selected (ranked) Population.
pub struct SelectedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    individuals: Vec<I>,
    fitness: Vec<F>,
    rank_dist: Vec<SolutionRankDist>,
}

impl<I> From<Vec<I>> for UnratedPopulation<I> where I: Clone
{
    fn from(v: Vec<I>) -> UnratedPopulation<I> {
        UnratedPopulation { individuals: v }
    }
}

impl<I> FromIterator<I> for UnratedPopulation<I> where I: Clone
{
    fn from_iter<T>(iterator: T) -> UnratedPopulation<I>
        where T: IntoIterator<Item = I>
    {
        UnratedPopulation { individuals: iterator.into_iter().collect() }
    }
}

impl<I> AsRef<[I]> for UnratedPopulation<I> where I: Clone
{
    fn as_ref(&self) -> &[I] {
        &self.individuals
    }
}

impl<I> UnratedPopulation<I> where I: Clone + Sync
{
    pub fn individuals(&self) -> &[I] {
        &self.individuals
    }

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, ind: I) {
        self.individuals.push(ind);
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<F, E>(self, eval: &E, weight: f64) -> RatedPopulation<I, F>
        where F: MultiObjective + Clone + Send,
              E: Sync + Fn(&I) -> F
    {
        let mut fitness = Vec::new();
        self.individuals.into_par_iter().map(eval).weight(weight).collect_into(&mut fitness);
        assert!(fitness.len() == self.individuals.len());

        RatedPopulation {
            individuals: self.individuals,
            fitness: fitness,
        }
    }
}

impl<I, F> RatedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> SelectedPopulation<I, F>
        where D: Domination<F>
    {
        // evaluate rank and crowding distance
        let rank_dist = select_solutions(&self.fitness,
                                         population_size,
                                         num_objectives,
                                         domination);
        assert!(rank_dist.len() <= population_size);
        SelectedPopulation {
            individuals: self.individuals,
            fitness: self.fitness,
            rank_dist: rank_dist,
        }
    }

    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.individuals.len()
    }

    pub fn fitness(&self) -> &[F] {
        &self.fitness
    }
}

impl<I, F> SelectedPopulation<I, F>
    where I: Clone,
          F: MultiObjective + Clone
{
    /// Generate an offspring population.
    /// XXX: Factor out selection into a separate Trait  SelectionMethod
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<I>
        where R: Rng,
              M: Fn(&mut R, &I, &I) -> I
    {
        assert!(self.individuals.len() == self.fitness.len());
        assert!(self.individuals.len() >= self.rank_dist.len());
        assert!(tournament_k > 0);

        let rank_dist = &self.rank_dist[..];

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<I> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| rank_dist[i1] < rank_dist[i2],
                                                       rank_dist.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                        (p1, p2)
                    } else if rank_dist[p2] < rank_dist[p1] {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    mate(rng, &self.individuals[p1], &self.individuals[p2])
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> SelectedPopulation<I, F> {
        SelectedPopulation {
            individuals: Vec::new(),
            fitness: Vec::new(),
            rank_dist: Vec::new(),
        }
    }

    pub fn len(&self) -> usize {
        // NOTE: the population and fitness arrays might still be larger.
        self.rank_dist.len()
    }

    /// Merging a selected population result in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<I, F>) -> RatedPopulation<I, F> {
        let mut new_ind = Vec::with_capacity(self.len() + offspring.len());
        let mut new_fit = Vec::with_capacity(self.len() + offspring.len());
        self.all(&mut |ind, fit| {
            // XXX: Optimize. Avoid clone
            new_ind.push(ind.clone());
            new_fit.push(fit.clone());
        });

        new_ind.extend(offspring.individuals);
        new_fit.extend(offspring.fitness);

        assert!(new_ind.len() == new_fit.len());

        RatedPopulation {
            individuals: new_ind,
            fitness: new_fit,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
        }
    }

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f32)
    {
        for rd in self.rank_dist.iter() {
            f(&self.individuals[rd.idx],
              &self.fitness[rd.idx],
              rd.rank as usize,
              rd.dist);
        }
    }

    // XXX: fitness_iter()
    pub fn fitness_to_vec(&self) -> Vec<F> {
        let mut v = Vec::new();
        self.all(&mut |_, f| v.push(f.clone()));
        v
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.rank_dist.iter().map(|rd| rd.rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&I, &F)
    {
        for rd in self.rank_dist.iter() {
            if rd.rank as usize == rank {
                f(&self.individuals[rd.idx], &self.fitness[rd.idx]);
            }
        }
    }
}
<|endoftext|>


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

use super::{Drawable, BoundingBox, MeasureMode};
use ::elements::{Element};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type StrokeWidthReader<T> = fn(&T) -> f32;
pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Element + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width_reader: StrokeWidthReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Element + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &self.start,
            &self.end,
            (self.color_reader)(self.element),
            (self.stroke_width_reader)(self.element),
        )
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = (self.stroke_width_reader)(self.element);

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        let mut width = (start.x()-end.x()).abs()+(x_diff*2.);
        let mut height = (start.y()-end.y()).abs()+(y_diff*2.);

        if width.is_nan() {
            width = 0.;
        }

        if height.is_nan() {
            height = 0.;
        }

        self.start = &start+&Point::new(x_diff, y_diff);
        self.end = &end+&Point::new(x_diff, y_diff);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width_reader: StrokeWidthReader<T>,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

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

    struct MockElement;
    impl Element for MockElement {
        fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }
}<commit_msg>Fix line not drawing relative to parent<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::elements::{Element};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type StrokeWidthReader<T> = fn(&T) -> f32;
pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Element + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width_reader: StrokeWidthReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Element + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &(&self.start+pen_pos),
            &(&self.end+pen_pos),
            (self.color_reader)(self.element),
            (self.stroke_width_reader)(self.element),
        )
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = (self.stroke_width_reader)(self.element);

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        let mut width = (start.x()-end.x()).abs()+(x_diff*2.);
        let mut height = (start.y()-end.y()).abs()+(y_diff*2.);

        if width.is_nan() {
            width = 0.;
        }

        if height.is_nan() {
            height = 0.;
        }

        self.start = &start+&Point::new(x_diff, y_diff);
        self.end = &end+&Point::new(x_diff, y_diff);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width_reader: StrokeWidthReader<T>,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

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

    struct MockElement;
    impl Element for MockElement {
        fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }
}<|endoftext|>


<commit_before>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling
//!
//! # Examples
//!
//! ```rust,macro_test
//! # #[macro_use] extern crate twig;
//! # fn main() {
//! use std::fmt;
//! use twig::error::{Error, ErrorCode};
//!
//! // Implement a custom error code.
//! #[derive(Debug)]
//! enum MySimpleErrorCode {
//!     Critical,
//!     Recoverable
//! }
//! type MySimpleError = Error<MySimpleErrorCode>;
//!
//! impl ErrorCode for MySimpleErrorCode {
//!     fn description(&self) -> &str {
//!         match *self {
//!             MySimpleErrorCode::Critical => "Critical error.",
//!             MySimpleErrorCode::Recoverable => "Recoverable error."
//!         }
//!     }
//! }
//!
//! impl fmt::Display for MySimpleErrorCode {
//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//!         write!(f, "{} With human readable details", self.description())
//!     }
//! }
//!
//! // Create a twig error, wrapping this error code + code location.
//! let result: Result<(), MySimpleError> = err!(MySimpleErrorCode::Critical);
//! if let Err(error) = result {
//!     assert_eq!(error.to_string(), "Critical error. With human readable details at <anon>:30:40\n");
//! }
//! # }
//! ```

use std::fmt::{self, Debug, Display};
use std::error;
use std::any::Any;

#[macro_use]
mod macros;
// use std Error-trait to improve cross-crate compatibility
// don't mix it up with Err(X)

/// Lightweight base functionality for error codes
///
/// Similar to std::error::Error, but _without_ error-chaining.
pub trait ErrorCode: Debug + Display + Any {
    /// A short description of the error code.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    fn description(&self) -> &str;

    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Error<Self> where
        Self: Sized
    {
        Error::new(self, location)
    }
}

/// Reference implementation to make examples easier.
impl ErrorCode for &'static str {
    fn description(&self) -> &str { *self }
}

/// Transform ErrorCodes
///
/// It is different to the Into-trait, because we only take references.
pub trait GeneralizeTo<T> {
    fn generalize(&self) -> T;
}

/// Record current state of complex objects
///
/// Implement this trait for complex objects. Make sure, that the Dump::Data type
/// does not contain lifetimes to keep error codes simple. In practice this means
/// cloning all referenced data into the dump.
///
/// For any `X: Dump` you can
///
/// * reference the associated type via `<X as Dump>::Data`
/// * create the dump via `X.dump()`
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic twig error
///
/// Wrapper around some `ErrorCode` - adds location support and error-chaining.
#[derive(Debug)]
pub struct Error<T>
    where T: ErrorCode
{
    // the exception codes are going to be enums
    // - i.e. Exception<MY_ENUM> implements std::error::Error without any boilerplate
    // to MY_ENUM. Hurray! :-)
    code: T,
    // I decided to call this field `code` instead of `error` to not confuse it with the Error trait
    location: Location,
    // chaining is required by std::error::Error
    cause: Option<Box<error::Error>>,
}

impl<T> Error<T>
    where T: ErrorCode
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// use twig::error::Error;
    ///
    /// Error::new("my error", loc!()); // shorthand: `err!("my error")`
    /// # }
    /// ```
    pub fn new(code: T, location: Location) -> Error<T> {
        Error {
            code: code,
            location: location,
            cause: None
        }
    }

    /// Return the associated error code.
    #[allow(dead_code)] // only used by tests
    pub fn code(&self) -> &T {
        &self.code
    }

    /// Return the location the error occured.
    pub fn location(&self) -> &Location {
        &self.location
    }

    /// Set the cause for this error.
    pub fn caused_by<X: 'static + error::Error>(mut self, cause: X) -> Self {
        self.cause = Some(Box::new(cause));

        self
    }

    /// Wraps this error inside another error as its cause.
    pub fn causes<X>(self, wrapper: Error<X>) -> Error<X> where
        X: ErrorCode
    {
        wrapper.caused_by(self)
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(self),
        }
    }
}

impl<T> error::Error for Error<T>
    where T: ErrorCode
{
    fn description(&self) -> &str {
        // delegate the error description to the ErrorCode
        &self.code.description()
    }

    fn cause<'a>(&'a self) -> Option<&'a error::Error> {
        // dereference from Option<Box<T>> to Option<&T>
        self.cause.as_ref().map(|x| &**x)
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a error::Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a error::Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Display for Error<T>
    where T: ErrorCode
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{error_code} at {location}\n",
            error_code = self.code,
            location = self.location));

        match self.cause {
            None => Ok(()),
            Some(ref cause) => write!(f, " - caused by: {}", cause),
        }
    }
}

/// Location in rust source code
///
/// The Display trait is formatted like `"{filename}:{line}:{column}"`.
///
/// We just store everything we can get, to identify source code locations. Note that
/// the module_path is currently only displayed in Debug output due to this redundancy.
/// You can access all fields directly.
#[derive(Debug)]
pub struct Location {
    pub module_path : &'static str, // e.g. twig::lexer::job::state::shared_traits
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<commit_msg>documentation<commit_after>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling
//!
//! # Examples
//!
//! ```rust,macro_test
//! # #[macro_use] extern crate twig;
//! # fn main() {
//! use std::fmt;
//! use twig::error::{Error, ErrorCode};
//!
//! // Implement a custom error code.
//! type MySimpleError = Error<MySimpleErrorCode>;
//!
//! #[derive(Debug)]
//! enum MySimpleErrorCode {
//!     Critical,
//!     Recoverable
//! }
//!
//! impl ErrorCode for MySimpleErrorCode {
//!     fn description(&self) -> &str {
//!         match *self {
//!             MySimpleErrorCode::Critical => "Critical error.",
//!             MySimpleErrorCode::Recoverable => "Recoverable error."
//!         }
//!     }
//! }
//!
//! impl fmt::Display for MySimpleErrorCode {
//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//!         write!(f, "{} With human readable details", self.description())
//!     }
//! }
//!
//! // Create a twig error, wrapping this error code + code location.
//! let result: Result<(), MySimpleError> = err!(MySimpleErrorCode::Critical);
//! if let Err(error) = result {
//!     assert_eq!(error.to_string(), "Critical error. With human readable details at <anon>:31:40\n");
//! }
//! # }
//! ```

use std::fmt::{self, Debug, Display};
use std::error;
use std::any::Any;

#[macro_use]
mod macros;
// use std Error-trait to improve cross-crate compatibility
// don't mix it up with Err(X)

/// Lightweight base functionality for error codes
///
/// Similar to std::error::Error, but _without_ error-chaining.
pub trait ErrorCode: Debug + Display + Any {
    /// A short description of the error code.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    fn description(&self) -> &str;

    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Error<Self> where
        Self: Sized
    {
        Error::new(self, location)
    }
}

/// Reference implementation to make examples easier.
impl ErrorCode for &'static str {
    fn description(&self) -> &str { *self }
}

/// Transform ErrorCodes
///
/// It is different to the Into-trait, because we only take references.
pub trait GeneralizeTo<T> {
    fn generalize(&self) -> T;
}

/// Record current state of complex objects
///
/// Implement this trait for complex objects. Make sure, that the Dump::Data type
/// does not contain lifetimes to keep error codes simple. In practice this means
/// cloning all referenced data into the dump.
///
/// For any `X: Dump` you can
///
/// * reference the associated type via `<X as Dump>::Data`
/// * create the dump via `X.dump()`
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic twig error
///
/// Wrapper around some `ErrorCode` - adds location support and error-chaining.
#[derive(Debug)]
pub struct Error<T>
    where T: ErrorCode
{
    // the exception codes are going to be enums
    // - i.e. Exception<MY_ENUM> implements std::error::Error without any boilerplate
    // to MY_ENUM. Hurray! :-)
    code: T,
    // I decided to call this field `code` instead of `error` to not confuse it with the Error trait
    location: Location,
    // chaining is required by std::error::Error
    cause: Option<Box<error::Error>>,
}

impl<T> Error<T>
    where T: ErrorCode
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// use twig::error::Error;
    ///
    /// Error::new("my error", loc!()); // shorthand: `err!("my error")`
    /// # }
    /// ```
    pub fn new(code: T, location: Location) -> Error<T> {
        Error {
            code: code,
            location: location,
            cause: None
        }
    }

    /// Return the associated error code.
    #[allow(dead_code)] // only used by tests
    pub fn code(&self) -> &T {
        &self.code
    }

    /// Return the location the error occured.
    pub fn location(&self) -> &Location {
        &self.location
    }

    /// Set the cause for this error.
    pub fn caused_by<X: 'static + error::Error>(mut self, cause: X) -> Self {
        self.cause = Some(Box::new(cause));

        self
    }

    /// Wraps this error inside another error as its cause.
    pub fn causes<X>(self, wrapper: Error<X>) -> Error<X> where
        X: ErrorCode
    {
        wrapper.caused_by(self)
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(self),
        }
    }
}

impl<T> error::Error for Error<T>
    where T: ErrorCode
{
    fn description(&self) -> &str {
        // delegate the error description to the ErrorCode
        &self.code.description()
    }

    fn cause<'a>(&'a self) -> Option<&'a error::Error> {
        // dereference from Option<Box<T>> to Option<&T>
        self.cause.as_ref().map(|x| &**x)
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a error::Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a error::Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Display for Error<T>
    where T: ErrorCode
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{error_code} at {location}\n",
            error_code = self.code,
            location = self.location));

        match self.cause {
            None => Ok(()),
            Some(ref cause) => write!(f, " - caused by: {}", cause),
        }
    }
}

/// Location in rust source code
///
/// The Display trait is formatted like `"{filename}:{line}:{column}"`.
///
/// We just store everything we can get, to identify source code locations. Note that
/// the module_path is currently only displayed in Debug output due to this redundancy.
/// You can access all fields directly.
#[derive(Debug)]
pub struct Location {
    pub module_path : &'static str, // e.g. twig::lexer::job::state::shared_traits
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufReader, Read};
use std::{str, vec, fmt};
use std::path;
use std::io;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use scopes;
use nameres;
use ast;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    MatchArm,
    Function,
    Crate,
    Let,
    IfLet,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

#[derive(Debug,Clone,Copy)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

#[derive(Debug,Clone,Copy)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

#[derive(Debug,Clone,Copy)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

#[derive(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>,  // generic types are evaluated lazily
    pub session: Rc<Session>,
}

impl Match {
    pub fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types,
            session: self.session.clone()
        }
    }
}

impl fmt::Debug for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?} |{}|, {:?}]",
               self.matchstr,
               self.filepath.to_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr,
               self.session)
    }
}

#[derive(Clone)]
pub struct Scope {
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Rc<Session>
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{ filepath: m.filepath.clone(), point: m.point, session: m.session.clone() }
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{:?}, {:?}, {:?}]",
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[derive(Debug,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[derive(Clone)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Iter<Path> {
        self.segments[self.segments.len()-1].types.iter()
    }

    pub fn from_vec(global: bool, v: Vec<&str>) -> Path {
        let segs = v
            .into_iter()
            .map(|x| PathSegment{ name: x.to_owned(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }

    pub fn from_svec(global: bool, v: Vec<String>) -> Path {
        let segs = v
            .into_iter()
            .map(|x| PathSegment{ name: x, types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }
}

impl fmt::Debug for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "P["));
        let mut first = true;
        for seg in &self.segments {
            if first {
                try!(write!(f, "{}", seg.name));
                first = false;
            } else {
                try!(write!(f, "::{}", seg.name));
            }

            if !seg.types.is_empty() {
                try!(write!(f, "<"));
                let mut tfirst = true;
                for typath in &seg.types {
                    if tfirst {
                        try!(write!(f, "{:?}", typath));
                        tfirst = false;
                    } else {
                        try!(write!(f, ",{:?}", typath))
                    }
                }
                try!(write!(f, ">"));
            }
        }
        write!(f, "]")
    }
}

#[derive(Debug,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[derive(Clone)]
pub struct PathSearch {
    pub path: Path,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Rc<Session>
}

impl fmt::Debug for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{:?}, {:?}, {:?}, {:?}]",
               self.path,
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

pub struct FileCache {
    raw_cache: RefCell<HashMap<path::PathBuf, Rc<String>>>,
    masked_cache: RefCell<HashMap<path::PathBuf, Rc<String>>>
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache {
            raw_cache: RefCell::new(HashMap::new()),
            masked_cache: RefCell::new(HashMap::new())
        }
    }
}

impl fmt::Debug for FileCache {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "<FileCache>")
    }
}

#[derive(Debug)]
pub struct Session {
    pub query_path: path::PathBuf,            // the input path of the query
    pub substitute_file: path::PathBuf,       // the temporary file
    file_cache: Rc<FileCache>                 // cache for file contents
}

impl Session {
    pub fn from_path(query_path: &path::Path, substitute_file: &path::Path) -> Rc<Session> {
        Rc::new(Session {
            query_path: query_path.to_path_buf(),
            substitute_file: substitute_file.to_path_buf(),
            file_cache: Rc::new(FileCache::new())
        })
    }

    pub fn derived(&self, path: &path::Path) -> Rc<Session> {
        Rc::new(Session {
            query_path: path.to_path_buf(),
            substitute_file: path.to_path_buf(),
            file_cache: self.file_cache.clone()
        })
    }

    pub fn open_file(&self, path: &path::Path) -> io::Result<File> {
        if path == self.query_path.as_path() {
            File::open(&self.substitute_file)
        } else {
            File::open(path)
        }
    }

    pub fn read_file(&self, path: &path::Path) -> Vec<u8> {
        let mut rawbytes = Vec::new();
        if let Ok(f) = self.open_file(path) {
            BufReader::new(f).read_to_end(&mut rawbytes).unwrap();
            // skip BOM bytes, if present
            if rawbytes.len() > 2 && rawbytes[0..3] == [0xEF, 0xBB, 0xBF] {
                let mut it = rawbytes.into_iter();
                it.next(); it.next(); it.next();
                it.collect()
            } else {
                rawbytes
            }
        } else {
            error!("read_file couldn't open {:?}. Returning empty string", path);
            Vec::new()
        }
    }

    pub fn load_file(&self, filepath: &path::Path) -> Rc<String> {
        let mut cache = self.file_cache.raw_cache.borrow_mut();
        cache.entry(filepath.to_path_buf()).or_insert_with(|| {
            let rawbytes = self.read_file(filepath);
            Rc::new(String::from_utf8(rawbytes).unwrap())
        }).clone()
    }

    pub fn load_file_and_mask_comments(&self, filepath: &path::Path) -> Rc<String> {
        let mut cache = self.file_cache.masked_cache.borrow_mut();
        cache.entry(filepath.to_path_buf()).or_insert_with(|| {
            let rawbytes = self.read_file(filepath);
            let src = str::from_utf8(&rawbytes).unwrap();
            Rc::new(scopes::mask_comments(src))
        }).clone()
    }
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> vec::IntoIter<Match> {
    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = &src[start..pos];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{:?}: contextstr is |{}|, searchstr is |{}|", completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let path = Path::from_vec(global, v);
            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces,
                                         session) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_owned(), filepath, pos, session);
            debug!("complete_from_file context is {:?}", context);
            context.map(|ty| {
                if let Ty::TyMatch(m) = ty {
                    for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                        out.push(m)
                    }
                }
            });
        }
    }
    out.into_iter()
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> Option<Match> {
    find_definition_(src, filepath, pos, session)
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = &src[start..end];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{:?}| |{:?}| {:?}", contextstr, searchstr, completetype);

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let segs = v
                .into_iter()
                .map(|x| PathSegment{ name: x.to_owned(), types: Vec::new() })
                .collect::<Vec<_>>();
            let path = Path{ global: global, segments: segs };

            nameres::resolve_path(&path, filepath, pos,
                                  SearchType::ExactMatch, Namespace::BothNamespaces,
                                  session).nth(0)
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_owned(), filepath, pos, session);
            debug!("context is {:?}", context);

            context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0)
                    }
                    _ => None
                }
            })
        }
    }
}
<commit_msg>core: no need to use a buffered reader if we just read the whole file<commit_after>use std::fs::File;
use std::io::Read;
use std::{str, vec, fmt};
use std::path;
use std::io;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;

use scopes;
use nameres;
use ast;

#[derive(Debug,Clone,Copy,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    MatchArm,
    Function,
    Crate,
    Let,
    IfLet,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

#[derive(Debug,Clone,Copy)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

#[derive(Debug,Clone,Copy)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

#[derive(Debug,Clone,Copy)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

#[derive(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>,  // generic types are evaluated lazily
    pub session: Rc<Session>,
}

impl Match {
    pub fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types,
            session: self.session.clone()
        }
    }
}

impl fmt::Debug for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?} |{}|, {:?}]",
               self.matchstr,
               self.filepath.to_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr,
               self.session)
    }
}

#[derive(Clone)]
pub struct Scope {
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Rc<Session>
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{ filepath: m.filepath.clone(), point: m.point, session: m.session.clone() }
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{:?}, {:?}, {:?}]",
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[derive(Debug,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[derive(Clone)]
pub struct Path {
    pub global: bool,
    pub segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Iter<Path> {
        self.segments[self.segments.len()-1].types.iter()
    }

    pub fn from_vec(global: bool, v: Vec<&str>) -> Path {
        let segs = v
            .into_iter()
            .map(|x| PathSegment{ name: x.to_owned(), types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }

    pub fn from_svec(global: bool, v: Vec<String>) -> Path {
        let segs = v
            .into_iter()
            .map(|x| PathSegment{ name: x, types: Vec::new() })
            .collect::<Vec<_>>();
        Path{ global: global, segments: segs }
    }
}

impl fmt::Debug for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "P["));
        let mut first = true;
        for seg in &self.segments {
            if first {
                try!(write!(f, "{}", seg.name));
                first = false;
            } else {
                try!(write!(f, "::{}", seg.name));
            }

            if !seg.types.is_empty() {
                try!(write!(f, "<"));
                let mut tfirst = true;
                for typath in &seg.types {
                    if tfirst {
                        try!(write!(f, "{:?}", typath));
                        tfirst = false;
                    } else {
                        try!(write!(f, ",{:?}", typath))
                    }
                }
                try!(write!(f, ">"));
            }
        }
        write!(f, "]")
    }
}

#[derive(Debug,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[derive(Clone)]
pub struct PathSearch {
    pub path: Path,
    pub filepath: path::PathBuf,
    pub point: usize,
    pub session: Rc<Session>
}

impl fmt::Debug for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{:?}, {:?}, {:?}, {:?}]",
               self.path,
               self.filepath.to_str(),
               self.point,
               self.session)
    }
}

pub struct FileCache {
    raw_cache: RefCell<HashMap<path::PathBuf, Rc<String>>>,
    masked_cache: RefCell<HashMap<path::PathBuf, Rc<String>>>
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache {
            raw_cache: RefCell::new(HashMap::new()),
            masked_cache: RefCell::new(HashMap::new())
        }
    }
}

impl fmt::Debug for FileCache {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "<FileCache>")
    }
}

#[derive(Debug)]
pub struct Session {
    pub query_path: path::PathBuf,            // the input path of the query
    pub substitute_file: path::PathBuf,       // the temporary file
    file_cache: Rc<FileCache>                 // cache for file contents
}

impl Session {
    pub fn from_path(query_path: &path::Path, substitute_file: &path::Path) -> Rc<Session> {
        Rc::new(Session {
            query_path: query_path.to_path_buf(),
            substitute_file: substitute_file.to_path_buf(),
            file_cache: Rc::new(FileCache::new())
        })
    }

    pub fn derived(&self, path: &path::Path) -> Rc<Session> {
        Rc::new(Session {
            query_path: path.to_path_buf(),
            substitute_file: path.to_path_buf(),
            file_cache: self.file_cache.clone()
        })
    }

    pub fn open_file(&self, path: &path::Path) -> io::Result<File> {
        if path == self.query_path.as_path() {
            File::open(&self.substitute_file)
        } else {
            File::open(path)
        }
    }

    pub fn read_file(&self, path: &path::Path) -> Vec<u8> {
        let mut rawbytes = Vec::new();
        if let Ok(mut f) = self.open_file(path) {
            f.read_to_end(&mut rawbytes).unwrap();
            // skip BOM bytes, if present
            if rawbytes.len() > 2 && rawbytes[0..3] == [0xEF, 0xBB, 0xBF] {
                let mut it = rawbytes.into_iter();
                it.next(); it.next(); it.next();
                it.collect()
            } else {
                rawbytes
            }
        } else {
            error!("read_file couldn't open {:?}. Returning empty string", path);
            Vec::new()
        }
    }

    pub fn load_file(&self, filepath: &path::Path) -> Rc<String> {
        let mut cache = self.file_cache.raw_cache.borrow_mut();
        cache.entry(filepath.to_path_buf()).or_insert_with(|| {
            let rawbytes = self.read_file(filepath);
            Rc::new(String::from_utf8(rawbytes).unwrap())
        }).clone()
    }

    pub fn load_file_and_mask_comments(&self, filepath: &path::Path) -> Rc<String> {
        let mut cache = self.file_cache.masked_cache.borrow_mut();
        cache.entry(filepath.to_path_buf()).or_insert_with(|| {
            let rawbytes = self.read_file(filepath);
            let src = str::from_utf8(&rawbytes).unwrap();
            Rc::new(scopes::mask_comments(src))
        }).clone()
    }
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> vec::IntoIter<Match> {
    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = &src[start..pos];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{:?}: contextstr is |{}|, searchstr is |{}|", completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let path = Path::from_vec(global, v);
            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces,
                                         session) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_owned(), filepath, pos, session);
            debug!("complete_from_file context is {:?}", context);
            context.map(|ty| {
                if let Ty::TyMatch(m) = ty {
                    for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                        out.push(m)
                    }
                }
            });
        }
    }
    out.into_iter()
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> Option<Match> {
    find_definition_(src, filepath, pos, session)
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: usize, session: &Rc<Session>) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = &src[start..end];

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{:?}| |{:?}| {:?}", contextstr, searchstr, completetype);

    match completetype {
        CompletionType::CompletePath => {
            let mut v = expr.split("::").collect::<Vec<_>>();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::old_io::blah
                v.remove(0);
                global = true;
            }

            let segs = v
                .into_iter()
                .map(|x| PathSegment{ name: x.to_owned(), types: Vec::new() })
                .collect::<Vec<_>>();
            let path = Path{ global: global, segments: segs };

            nameres::resolve_path(&path, filepath, pos,
                                  SearchType::ExactMatch, Namespace::BothNamespaces,
                                  session).nth(0)
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_owned(), filepath, pos, session);
            debug!("context is {:?}", context);

            context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0)
                    }
                    _ => None
                }
            })
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate ncollide_transformation;
extern crate kiss3d;
extern crate nalgebra as na;

use std::str::FromStr;
use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, RwLock};
use std::path::Path;
use std::time::Instant;
use rand::random;
use na::{Vector3, Translation};
use kiss3d::window::Window;
use kiss3d::light::Light;
use kiss3d::loader::obj;
use kiss3d::resource::{BufferType, AllocationType, GPUVec, Mesh};

fn usage(exe_name: &str) {
    println!("Usage: {} obj_file scale clusters concavity", exe_name);
    println!("");
    println!("Options:");
    println!("    obj_file  - the obj file to decompose.");
    println!("    scale     - the scale to apply to the displayed model.");
    println!("    clusters  - minimum number of clusters.");
    println!("    concavity - the maximum concavity accepted by the decomposition.");
}

fn main() {
    /*
     * Parse arguments.
     */
    let mut args = env::args();
    let exname = args.next().unwrap();

    if args.len() != 4 {
        usage(&exname[..]);
        return;
    }

    let path = &args.next().unwrap()[..];
    let scale: f32 = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let clusters: usize = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let concavity: f32 = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let scale = Vector3::new(scale, scale, scale);

    /*
     * Create the window.
     */
    let mut window = Window::new("Kiss3d: convex decomposition");

    /*
     * Convex decomposition.
     */
    let obj_path = Path::new(path);
    // let obj_path = Path::new("/home/tortue/Downloads/models/ATST_medium.obj");
    let mtl_path = Path::new("none");
    let teapot   = obj::parse_file(&obj_path, &mtl_path, "none").unwrap();

    let mut m = window.add_obj(&obj_path, &mtl_path, scale);
    m.set_surface_rendering_activation(false);
    // m.set_lines_width(1.0);
    let data    = m.data();
    let coords  = data.object().expect("here").mesh().borrow().coords().clone();
    let normals = data.object().unwrap().mesh().borrow().normals().clone();
    let uvs     = data.object().unwrap().mesh().borrow().uvs().clone();
    let faces   = data.object().unwrap().mesh().borrow().faces().clone();

    // println!("objs: {}", teapot.len());

    let mut total_time = 0.0f64;
    for &(_, ref mesh, _) in teapot.iter() {
        match mesh.to_trimesh() {
            Some(mut trimesh) => {
                trimesh.split_index_buffer(true);
                let begin = Instant();
                let (decomp, partitioning) = ncollide_transformation::hacd(trimesh, concavity, clusters);
                let elapsed = begin.elapsed();
                total_time = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1000000000.0;

                println!("num comps: {}", decomp.len());

                for (comp, partitioning) in decomp.into_iter().zip(partitioning.into_iter()) {
                    let r = random();
                    let g = random();
                    let b = random();

                    let mut m  = window.add_trimesh(comp, scale);
                    m.set_color(r, g, b);
                    m.append_translation(&Vector3::new(-0.1, 0.1, 0.0));
                    // m.set_surface_rendering_activation(false);
                    // m.enable_backface_culling(false);
                    // m.set_lines_width(1.0);

                    let mut part_faces = Vec::new();

                    for i in partitioning.into_iter() {
                        part_faces.push(faces.read().unwrap().data().as_ref().unwrap()[i]);
                    }

                    let faces = GPUVec::new(part_faces, BufferType::ElementArray, AllocationType::StaticDraw);
                    let faces = Arc::new(RwLock::new(faces));

                    let mesh = Mesh::new_with_gpu_vectors(coords.clone(), faces, normals.clone(), uvs.clone());
                    let mesh = Rc::new(RefCell::new(mesh));
                    let mut m  = window.add_mesh(mesh, scale);
                    m.set_color(r, g, b);
                    m.append_translation(&Vector3::new(0.1, 0.1, 0.0));
                    // m.set_surface_rendering_activation(false);
                    // m.enable_backface_culling(false);
                    m.set_lines_width(1.0);
                }
            },
            None => { }
        }
    }

    println!("Decomposition time: {}", total_time);

    /*
     *
     * Rendering.
     *
     */
    window.set_light(Light::StickToCamera);

    while window.render() {
    }
}
<commit_msg>Fix typo in decomp example<commit_after>extern crate rand;
extern crate ncollide_transformation;
extern crate kiss3d;
extern crate nalgebra as na;

use std::str::FromStr;
use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, RwLock};
use std::path::Path;
use std::time::Instant;
use rand::random;
use na::{Vector3, Translation};
use kiss3d::window::Window;
use kiss3d::light::Light;
use kiss3d::loader::obj;
use kiss3d::resource::{BufferType, AllocationType, GPUVec, Mesh};

fn usage(exe_name: &str) {
    println!("Usage: {} obj_file scale clusters concavity", exe_name);
    println!("");
    println!("Options:");
    println!("    obj_file  - the obj file to decompose.");
    println!("    scale     - the scale to apply to the displayed model.");
    println!("    clusters  - minimum number of clusters.");
    println!("    concavity - the maximum concavity accepted by the decomposition.");
}

fn main() {
    /*
     * Parse arguments.
     */
    let mut args = env::args();
    let exname = args.next().unwrap();

    if args.len() != 4 {
        usage(&exname[..]);
        return;
    }

    let path = &args.next().unwrap()[..];
    let scale: f32 = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let clusters: usize = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let concavity: f32 = FromStr::from_str(&args.next().unwrap()[..]).unwrap();
    let scale = Vector3::new(scale, scale, scale);

    /*
     * Create the window.
     */
    let mut window = Window::new("Kiss3d: convex decomposition");

    /*
     * Convex decomposition.
     */
    let obj_path = Path::new(path);
    // let obj_path = Path::new("/home/tortue/Downloads/models/ATST_medium.obj");
    let mtl_path = Path::new("none");
    let teapot   = obj::parse_file(&obj_path, &mtl_path, "none").unwrap();

    let mut m = window.add_obj(&obj_path, &mtl_path, scale);
    m.set_surface_rendering_activation(false);
    // m.set_lines_width(1.0);
    let data    = m.data();
    let coords  = data.object().expect("here").mesh().borrow().coords().clone();
    let normals = data.object().unwrap().mesh().borrow().normals().clone();
    let uvs     = data.object().unwrap().mesh().borrow().uvs().clone();
    let faces   = data.object().unwrap().mesh().borrow().faces().clone();

    // println!("objs: {}", teapot.len());

    let mut total_time = 0.0f64;
    for &(_, ref mesh, _) in teapot.iter() {
        match mesh.to_trimesh() {
            Some(mut trimesh) => {
                trimesh.split_index_buffer(true);
                let begin = Instant::now();
                let (decomp, partitioning) = ncollide_transformation::hacd(trimesh, concavity, clusters);
                let elapsed = begin.elapsed();
                total_time = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1000000000.0;

                println!("num comps: {}", decomp.len());

                for (comp, partitioning) in decomp.into_iter().zip(partitioning.into_iter()) {
                    let r = random();
                    let g = random();
                    let b = random();

                    let mut m  = window.add_trimesh(comp, scale);
                    m.set_color(r, g, b);
                    m.append_translation(&Vector3::new(-0.1, 0.1, 0.0));
                    // m.set_surface_rendering_activation(false);
                    // m.enable_backface_culling(false);
                    // m.set_lines_width(1.0);

                    let mut part_faces = Vec::new();

                    for i in partitioning.into_iter() {
                        part_faces.push(faces.read().unwrap().data().as_ref().unwrap()[i]);
                    }

                    let faces = GPUVec::new(part_faces, BufferType::ElementArray, AllocationType::StaticDraw);
                    let faces = Arc::new(RwLock::new(faces));

                    let mesh = Mesh::new_with_gpu_vectors(coords.clone(), faces, normals.clone(), uvs.clone());
                    let mesh = Rc::new(RefCell::new(mesh));
                    let mut m  = window.add_mesh(mesh, scale);
                    m.set_color(r, g, b);
                    m.append_translation(&Vector3::new(0.1, 0.1, 0.0));
                    // m.set_surface_rendering_activation(false);
                    // m.enable_backface_culling(false);
                    m.set_lines_width(1.0);
                }
            },
            None => { }
        }
    }

    println!("Decomposition time: {}", total_time);

    /*
     *
     * Rendering.
     *
     */
    window.set_light(Light::StickToCamera);

    while window.render() {
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use cgmath::Point2;

use crate::bsdf::BSDF;
use crate::color::Color;
use crate::float::*;
use crate::obj_load;
use crate::texture::Texture;

mod diffuse;
mod glossy;
mod specular;

use self::diffuse::*;
use self::glossy::*;
use self::specular::*;

/// Scattering model over the whole surface
pub trait ScatteringT {
    /// Get the local scattering functions
    fn local(&self, tex_coords: Point2<Float>) -> BSDF;
    /// The texture to use for preview rendering
    fn preview_texture(&self) -> &Texture;
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum Scattering {
    DR(DiffuseReflection),
    GB(GlossyBlend),
    GR(GlossyReflection),
    GT(GlossyTransmission),
    SR(SpecularReflection),
    ST(SpecularTransmission),
}

fn diffuse_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.tex_diffuse {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.c_diffuse.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn specular_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.tex_specular {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.c_specular.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn transmissive_texture(obj_mat: &obj_load::Material) -> Texture {
    let color = Color::from(
        obj_mat
            .c_translucency
            .expect("No translucent color for translucent material"),
    );
    // MTL spec states that transmissive color defines light that is able to pass through
    // but some scenes seem to interpret it as a filter that removes light
    let color = Color::white() - color;
    Texture::from_color(color)
}

impl Scattering {
    pub fn from_obj(obj_mat: &obj_load::Material) -> Self {
        use self::Scattering::*;

        let diffuse = diffuse_texture(obj_mat);
        let specular = specular_texture(obj_mat);
        match obj_mat.illumination_model.unwrap_or(0) {
            2 => {
                let shininess = obj_mat.shininess.unwrap().to_float();
                if diffuse.is_black() {
                    GR(GlossyReflection::new(specular, shininess))
                } else if specular.is_black() {
                    DR(DiffuseReflection::new(diffuse))
                } else {
                    GB(GlossyBlend::new(diffuse, specular, shininess))
                }
            }
            5 => {
                let texture = specular_texture(obj_mat);
                SR(SpecularReflection::new(texture))
            }
            4 | 6 | 7 => {
                let transmissive = transmissive_texture(obj_mat);
                let shininess = obj_mat.shininess.unwrap().to_float();
                let eta = obj_mat
                    .refraction_i
                    .expect("No index of refraction for translucent material")
                    .to_float();
                if (eta - 1.0) < crate::consts::EPSILON {
                    // Glossy does not handle eta = 1 properly
                    // and the distribution would be the same anyways
                    ST(SpecularTransmission::new(specular, transmissive, eta))
                } else {
                    GT(GlossyTransmission::new(
                        specular,
                        transmissive,
                        shininess,
                        eta,
                    ))
                }
            }
            i => {
                if i > 10 {
                    println!("Illumination model {} is not defined in the mtl spec!", i);
                    println!("Defaulting to diffuse BSDF.");
                }
                DR(DiffuseReflection::new(diffuse))
            }
        }
    }
}

impl Deref for Scattering {
    type Target = dyn ScatteringT;

    fn deref(&self) -> &Self::Target {
        use self::Scattering::*;
        match self {
            DR(inner) => inner,
            GB(inner) => inner,
            GR(inner) => inner,
            GT(inner) => inner,
            SR(inner) => inner,
            ST(inner) => inner,
        }
    }
}
<commit_msg>Fix eta check<commit_after>use std::ops::Deref;

use cgmath::Point2;

use crate::bsdf::BSDF;
use crate::color::Color;
use crate::float::*;
use crate::obj_load;
use crate::texture::Texture;

mod diffuse;
mod glossy;
mod specular;

use self::diffuse::*;
use self::glossy::*;
use self::specular::*;

/// Scattering model over the whole surface
pub trait ScatteringT {
    /// Get the local scattering functions
    fn local(&self, tex_coords: Point2<Float>) -> BSDF;
    /// The texture to use for preview rendering
    fn preview_texture(&self) -> &Texture;
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum Scattering {
    DR(DiffuseReflection),
    GB(GlossyBlend),
    GR(GlossyReflection),
    GT(GlossyTransmission),
    SR(SpecularReflection),
    ST(SpecularTransmission),
}

fn diffuse_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.tex_diffuse {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.c_diffuse.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn specular_texture(obj_mat: &obj_load::Material) -> Texture {
    match &obj_mat.tex_specular {
        Some(path) => Texture::from_image_path(path),
        None => {
            let color = Color::from(obj_mat.c_specular.unwrap_or([0.0, 0.0, 0.0]));
            Texture::from_color(color)
        }
    }
}

fn transmissive_texture(obj_mat: &obj_load::Material) -> Texture {
    let color = Color::from(
        obj_mat
            .c_translucency
            .expect("No translucent color for translucent material"),
    );
    // MTL spec states that transmissive color defines light that is able to pass through
    // but some scenes seem to interpret it as a filter that removes light
    let color = Color::white() - color;
    Texture::from_color(color)
}

impl Scattering {
    pub fn from_obj(obj_mat: &obj_load::Material) -> Self {
        use self::Scattering::*;

        let diffuse = diffuse_texture(obj_mat);
        let specular = specular_texture(obj_mat);
        match obj_mat.illumination_model.unwrap_or(0) {
            2 => {
                let shininess = obj_mat.shininess.unwrap().to_float();
                if diffuse.is_black() {
                    GR(GlossyReflection::new(specular, shininess))
                } else if specular.is_black() {
                    DR(DiffuseReflection::new(diffuse))
                } else {
                    GB(GlossyBlend::new(diffuse, specular, shininess))
                }
            }
            5 => {
                let texture = specular_texture(obj_mat);
                SR(SpecularReflection::new(texture))
            }
            4 | 6 | 7 => {
                let transmissive = transmissive_texture(obj_mat);
                let shininess = obj_mat.shininess.unwrap().to_float();
                let eta = obj_mat
                    .refraction_i
                    .expect("No index of refraction for translucent material")
                    .to_float();
                if (eta - 1.0).abs() < crate::consts::EPSILON {
                    // Glossy does not handle eta = 1 properly
                    // and the distribution would be the same anyways
                    ST(SpecularTransmission::new(specular, transmissive, eta))
                } else {
                    GT(GlossyTransmission::new(
                        specular,
                        transmissive,
                        shininess,
                        eta,
                    ))
                }
            }
            i => {
                if i > 10 {
                    println!("Illumination model {} is not defined in the mtl spec!", i);
                    println!("Defaulting to diffuse BSDF.");
                }
                DR(DiffuseReflection::new(diffuse))
            }
        }
    }
}

impl Deref for Scattering {
    type Target = dyn ScatteringT;

    fn deref(&self) -> &Self::Target {
        use self::Scattering::*;
        match self {
            DR(inner) => inner,
            GB(inner) => inner,
            GR(inner) => inner,
            GT(inner) => inner,
            SR(inner) => inner,
            ST(inner) => inner,
        }
    }
}
<|endoftext|>