<commit_before>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::select_solutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F> where F: MultiObjective, G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F> where F: MultiObjective, G: Send {
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }
}

impl<G, F> Individual<G, F> where F: MultiObjective, G: Send {
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            selected: false,
        }
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

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

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

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

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation {
            individuals: individuals,
        }
    }
}

impl<G, F> RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> RankedPopulation<G, F>
        where D: Domination<F>
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance
        select_solutions(&mut individuals,
                         population_size,
                         num_objectives,
                         domination);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        assert!(individuals.len() == population_size);

        RankedPopulation {
            individuals: individuals,
        }
    }

    pub fn new() -> Self {
        RatedPopulation {
            individuals: Vec::new(),
        }
    }

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

    pub fn fitness(&self, index: usize) -> &F {
        self.individuals[index].fitness.as_ref().unwrap()
    }

    pub fn fitness_mut(&mut self, index: usize) -> &mut F {
        self.individuals[index].fitness.as_mut().unwrap()
    }
}

impl<G, F> RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    /// Generate an unrated 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<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

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

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.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 self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

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

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

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation {
            individuals: Vec::new(),
        }
    }

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

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation {
            individuals: individuals,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

/*

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f64)
    {
        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
    }

    */
}
<commit_msg>Add individuals() accessor and fitness()/fitness_mut()<commit_after>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::select_solutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F> where F: MultiObjective, G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F> where F: MultiObjective, G: Send {
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }
}

impl<G, F> Individual<G, F> where F: MultiObjective, G: Send {
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            selected: false,
        }
    }

    pub fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    pub fn fitness_mut(&mut self) -> &mut F {
        self.fitness.as_mut().unwrap()
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

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

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

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

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation {
            individuals: individuals,
        }
    }
}

impl<G, F> RatedPopulation<G, F> where F: MultiObjective, G: Send
{
    pub fn select<D>(self,
                     population_size: usize,
                     num_objectives: usize,
                     domination: &mut D)
                     -> RankedPopulation<G, F>
        where D: Domination<F>
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance
        select_solutions(&mut individuals,
                         population_size,
                         num_objectives,
                         domination);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        assert!(individuals.len() == population_size);

        RankedPopulation {
            individuals: individuals,
        }
    }

    pub fn new() -> Self {
        RatedPopulation {
            individuals: Vec::new(),
        }
    }

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

    pub fn fitness(&self, index: usize) -> &F {
        self.individuals[index].fitness.as_ref().unwrap()
    }

    pub fn fitness_mut(&mut self, index: usize) -> &mut F {
        self.individuals[index].fitness.as_mut().unwrap()
    }
}

impl<G, F> RankedPopulation<G, F> where F: MultiObjective, G: Send
{
    /// Generate an unrated 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<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

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

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.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 self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

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

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

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation {
            individuals: Vec::new(),
        }
    }

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

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation {
            individuals: individuals,
        }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

/*

    pub fn all_with_rank_dist<C>(&self, f: &mut C)
        where C: FnMut(&I, &F, usize, f64)
    {
        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
    }

    */
}
<|endoftext|>


<commit_before>//! Search interface

use std::collections::HashMap;
use std::fmt;

use hyper::client::Connect;
use serde::de::DeserializeOwned;
use url::{self, form_urlencoded};

use {Github, Stream, Future, SortDirection, unfold};
use labels::Label;
use users::User;

mod repos;
use self::repos::SearchRepos;

/// Sort directions for pull requests
#[derive(Debug, PartialEq)]
pub enum IssuesSort {
    /// Sort by time created
    Created,
    /// Sort by last updated
    Updated,
    /// Sort by number of comments
    Comments,
}

impl fmt::Display for IssuesSort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IssuesSort::Comments => "comments",
            IssuesSort::Created => "created",
            IssuesSort::Updated => "updated",
        }.fmt(f)
    }
}

/// Provides access to search operations
/// https://developer.github.com/v3/search/#search-issues
#[derive(Clone)]
pub struct Search<C>
where
    C: Clone + Connect,
{
    github: Github<C>,
}

fn items<D>(result: SearchResult<D>) -> Vec<D>
where
    D: DeserializeOwned + 'static,
{
    result.items
}

impl<C: Clone + Connect> Search<C> {
    #[doc(hidden)]
    pub fn new(github: Github<C>) -> Self {
        Self { github }
    }

    /// return a reference to a search interface for issues
    pub fn issues(&self) -> SearchIssues<C> {
        SearchIssues::new(self.clone())
    }

    /// Return a reference to a search interface for repositories
    pub fn repos(&self) -> SearchRepos<C> {
        SearchRepos::new(self.clone())
    }

    fn iter<D>(&self, url: &str) -> Stream<D>
    where
        D: DeserializeOwned + 'static,
    {
        unfold(self.github.clone(), self.github.get_pages(url), items)
    }

    fn search<D>(&self, url: &str) -> Future<SearchResult<D>>
    where
        D: DeserializeOwned + 'static,
    {
        self.github.get(url)
    }
}

/// Provides access to issue search operations
/// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssues<C>
where
    C: Clone + Connect,
{
    search: Search<C>,
}

impl<C: Clone + Connect> SearchIssues<C> {
    #[doc(hidden)]
    pub fn new(search: Search<C>) -> Self {
        Self { search }
    }

    fn search_uri<Q>(&self, q: Q, options: &SearchIssuesOptions) -> String
    where
        Q: Into<String>,
    {
        let mut uri = vec!["/search/issues".to_string()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query = form_urlencoded::Serializer::new(query_options)
            .append_pair("q", &q.into())
            .finish();
        uri.push(query);
        uri.join("?")
    }

    /// Returns an Iterator over pages of search results
    /// Use this interface if you wish to iterate over all items
    /// in a result set
    pub fn iter<Q>(&self, q: Q, options: &SearchIssuesOptions) -> Stream<IssuesItem>
    where
        Q: Into<String>,
    {
        self.search.iter::<IssuesItem>(&self.search_uri(q, options))
    }

    /// Returns a single page of search results
    pub fn list<Q>(&self, q: Q, options: &SearchIssuesOptions) -> Future<SearchResult<IssuesItem>>
    where
        Q: Into<String>,
    {
        self.search.search::<IssuesItem>(
            &self.search_uri(q, options),
        )
    }
}

// representations (todo: replace with derive_builder)

#[derive(Default)]
pub struct SearchIssuesOptions {
    params: HashMap<&'static str, String>,
}

impl SearchIssuesOptions {
    pub fn builder() -> SearchIssuesOptionsBuilder {
        SearchIssuesOptionsBuilder::new()
    }

    /// serialize options as a string. returns None if no options are defined
    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssuesOptionsBuilder(SearchIssuesOptions);

impl SearchIssuesOptionsBuilder {
    pub fn new() -> SearchIssuesOptionsBuilder {
        SearchIssuesOptionsBuilder(SearchIssuesOptions { ..Default::default() })
    }

    pub fn per_page(&mut self, n: usize) -> &mut Self {
        self.0.params.insert("per_page", n.to_string());
        self
    }

    pub fn sort(&mut self, sort: IssuesSort) -> &mut Self {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn order(&mut self, direction: SortDirection) -> &mut Self {
        self.0.params.insert("order", direction.to_string());
        self
    }

    pub fn build(&self) -> SearchIssuesOptions {
        SearchIssuesOptions { params: self.0.params.clone() }
    }
}

#[derive(Debug, Deserialize)]
pub struct SearchResult<D> {
    pub total_count: u64,
    pub incomplete_results: bool,
    pub items: Vec<D>,
}

#[derive(Debug, Deserialize)]
pub struct IssuesItem {
    pub url: String,
    pub repository_url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub id: u64,
    pub number: u64,
    pub title: String,
    pub user: User,
    pub labels: Vec<Label>,
    pub state: String,
    pub locked: bool,
    pub assignee: Option<User>,
    pub assignees: Vec<User>,
    pub comments: u64,
    pub created_at: String,
    pub updated_at: String,
    pub closed_at: Option<String>,
    pub pull_request: Option<PullRequestInfo>,
    pub body: Option<String>,
}

impl IssuesItem {
    /// returns a tuple of (repo owner name, repo name) associated with this issue
    pub fn repo_tuple(&self) -> (String, String) {
        let parsed = url::Url::parse(&self.repository_url).unwrap();
        let path = parsed.path().split("/").collect::<Vec<_>>();
        (path[0].to_owned(), path[1].to_owned())
    }
}

#[derive(Debug, Deserialize)]
pub struct PullRequestInfo {
    pub url: String,
    pub html_url: String,
    pub diff_url: String,
    pub patch_url: String,
}
<commit_msg>Reexported all types of repos.rs<commit_after>//! Search interface

use std::collections::HashMap;
use std::fmt;

use hyper::client::Connect;
use serde::de::DeserializeOwned;
use url::{self, form_urlencoded};

use {Github, Stream, Future, SortDirection, unfold};
use labels::Label;
use users::User;

mod repos;
use self::repos::SearchRepos;

pub use self::repos::*;

/// Sort directions for pull requests
#[derive(Debug, PartialEq)]
pub enum IssuesSort {
    /// Sort by time created
    Created,
    /// Sort by last updated
    Updated,
    /// Sort by number of comments
    Comments,
}

impl fmt::Display for IssuesSort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IssuesSort::Comments => "comments",
            IssuesSort::Created => "created",
            IssuesSort::Updated => "updated",
        }.fmt(f)
    }
}

/// Provides access to search operations
/// https://developer.github.com/v3/search/#search-issues
#[derive(Clone)]
pub struct Search<C>
where
    C: Clone + Connect,
{
    github: Github<C>,
}

fn items<D>(result: SearchResult<D>) -> Vec<D>
where
    D: DeserializeOwned + 'static,
{
    result.items
}

impl<C: Clone + Connect> Search<C> {
    #[doc(hidden)]
    pub fn new(github: Github<C>) -> Self {
        Self { github }
    }

    /// return a reference to a search interface for issues
    pub fn issues(&self) -> SearchIssues<C> {
        SearchIssues::new(self.clone())
    }

    /// Return a reference to a search interface for repositories
    pub fn repos(&self) -> SearchRepos<C> {
        SearchRepos::new(self.clone())
    }

    fn iter<D>(&self, url: &str) -> Stream<D>
    where
        D: DeserializeOwned + 'static,
    {
        unfold(self.github.clone(), self.github.get_pages(url), items)
    }

    fn search<D>(&self, url: &str) -> Future<SearchResult<D>>
    where
        D: DeserializeOwned + 'static,
    {
        self.github.get(url)
    }
}

/// Provides access to issue search operations
/// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssues<C>
where
    C: Clone + Connect,
{
    search: Search<C>,
}

impl<C: Clone + Connect> SearchIssues<C> {
    #[doc(hidden)]
    pub fn new(search: Search<C>) -> Self {
        Self { search }
    }

    fn search_uri<Q>(&self, q: Q, options: &SearchIssuesOptions) -> String
    where
        Q: Into<String>,
    {
        let mut uri = vec!["/search/issues".to_string()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query = form_urlencoded::Serializer::new(query_options)
            .append_pair("q", &q.into())
            .finish();
        uri.push(query);
        uri.join("?")
    }

    /// Returns an Iterator over pages of search results
    /// Use this interface if you wish to iterate over all items
    /// in a result set
    pub fn iter<Q>(&self, q: Q, options: &SearchIssuesOptions) -> Stream<IssuesItem>
    where
        Q: Into<String>,
    {
        self.search.iter::<IssuesItem>(&self.search_uri(q, options))
    }

    /// Returns a single page of search results
    pub fn list<Q>(&self, q: Q, options: &SearchIssuesOptions) -> Future<SearchResult<IssuesItem>>
    where
        Q: Into<String>,
    {
        self.search.search::<IssuesItem>(
            &self.search_uri(q, options),
        )
    }
}

// representations (todo: replace with derive_builder)

#[derive(Default)]
pub struct SearchIssuesOptions {
    params: HashMap<&'static str, String>,
}

impl SearchIssuesOptions {
    pub fn builder() -> SearchIssuesOptionsBuilder {
        SearchIssuesOptionsBuilder::new()
    }

    /// serialize options as a string. returns None if no options are defined
    pub fn serialize(&self) -> Option<String> {
        if self.params.is_empty() {
            None
        } else {
            let encoded: String = form_urlencoded::Serializer::new(String::new())
                .extend_pairs(&self.params)
                .finish();
            Some(encoded)
        }
    }
}

/// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssuesOptionsBuilder(SearchIssuesOptions);

impl SearchIssuesOptionsBuilder {
    pub fn new() -> SearchIssuesOptionsBuilder {
        SearchIssuesOptionsBuilder(SearchIssuesOptions { ..Default::default() })
    }

    pub fn per_page(&mut self, n: usize) -> &mut Self {
        self.0.params.insert("per_page", n.to_string());
        self
    }

    pub fn sort(&mut self, sort: IssuesSort) -> &mut Self {
        self.0.params.insert("sort", sort.to_string());
        self
    }

    pub fn order(&mut self, direction: SortDirection) -> &mut Self {
        self.0.params.insert("order", direction.to_string());
        self
    }

    pub fn build(&self) -> SearchIssuesOptions {
        SearchIssuesOptions { params: self.0.params.clone() }
    }
}

#[derive(Debug, Deserialize)]
pub struct SearchResult<D> {
    pub total_count: u64,
    pub incomplete_results: bool,
    pub items: Vec<D>,
}

#[derive(Debug, Deserialize)]
pub struct IssuesItem {
    pub url: String,
    pub repository_url: String,
    pub labels_url: String,
    pub comments_url: String,
    pub events_url: String,
    pub html_url: String,
    pub id: u64,
    pub number: u64,
    pub title: String,
    pub user: User,
    pub labels: Vec<Label>,
    pub state: String,
    pub locked: bool,
    pub assignee: Option<User>,
    pub assignees: Vec<User>,
    pub comments: u64,
    pub created_at: String,
    pub updated_at: String,
    pub closed_at: Option<String>,
    pub pull_request: Option<PullRequestInfo>,
    pub body: Option<String>,
}

impl IssuesItem {
    /// returns a tuple of (repo owner name, repo name) associated with this issue
    pub fn repo_tuple(&self) -> (String, String) {
        let parsed = url::Url::parse(&self.repository_url).unwrap();
        let path = parsed.path().split("/").collect::<Vec<_>>();
        (path[0].to_owned(), path[1].to_owned())
    }
}

#[derive(Debug, Deserialize)]
pub struct PullRequestInfo {
    pub url: String,
    pub html_url: String,
    pub diff_url: String,
    pub patch_url: String,
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate color;
extern crate glutil;
extern crate calx;

use std::cmp::max;
use glutil::app::App;
use glutil::app;
use cgmath::aabb::{Aabb, Aabb2};
use cgmath::point::{Point, Point2};
use cgmath::vector::{Vec2};
use color::rgb::{ToRGB, consts};
use calx::rectutil::RectUtil;

static WHAT_DO_YOU_THINK_NIGHTMARE_DOG: &'static str =
"This is of no consequence, the new Tower of Babel nears completion. All \
humanity will be made whole again, a nightmare god of flesh and bone, singing \
one chorus with its million mouths.";

enum Align {
    Left,
    Center,
    Right
}

fn print_words<C: ToRGB>(
    app: &mut App, area: &Aabb2<f32>, color: &C, align: Align, text: &str) {
    let words: ~[&str] = text.split(' ').collect();
    let bounds = words.map(|&w| app.string_bounds(w).dim().x as uint);
    let mut i = 0;
    let origin = area.min().add_v(&Vec2::new(0.0, app::FONT_HEIGHT)).to_vec();
    let width = area.dim().x;
    let max_lines = (area.dim().y / app::FONT_HEIGHT) as uint;
    let mut pos = origin;
    let mut line = 0;
    while i < words.len() && line < max_lines {
        let (n, len) = num_fitting_words(width as uint, app::FONT_SPACE as uint, bounds.slice(i, bounds.len()));
        let n = max(1, n);

        let diff = area.dim().x - len as f32;
        match align {
            Left => (),
            Center => { pos.x += diff / 2.0; },
            Right => { pos.x += diff; },
        }
        for j in range(i, i + n) {
            app.draw_string(&pos, color, words[j]);
            pos.x += bounds[j] as f32 + app::FONT_SPACE;
        }
        i += n;
        pos.x = origin.x;
        pos.y += app::FONT_HEIGHT;
        line += 1;
    }

    fn num_fitting_words(span: uint, space: uint, lengths: &[uint]) -> (uint, uint) {
        if lengths.len() == 0 { return (0, 0) }
        let mut total = lengths[0];
        for i in range(1, lengths.len()) {
            let new_total = total + space + lengths[i];
            if new_total > span {
                return (i, total);
            }
            total = new_total;
        }
        return (lengths.len(), total);
    }
}

fn outline_print<C: ToRGB>(
    app: &mut App, area: &Aabb2<f32>, color: &C, align: Align, text: &str) {
    print_words(app, &area.add_v(&Vec2::new(-1.0f32, 1.0f32)), &consts::BLACK, align, text);
    print_words(app, area, color, align, text);
}

pub fn main() {
    let mut app = App::new(640, 360, "Shiny!");

    while app.alive {
        app.fill_rect(&RectUtil::new(0.0f32, 0.0f32, 640.0f32, 360.0f32), &consts::MIDNIGHTBLUE);

        let text_zone = Aabb2::new(Point2::new(4.0f32, 200.0f32), Point2::new(240.0f32, 360.0f32));
        outline_print(&mut app, &text_zone,
            &consts::LIGHTSLATEGRAY, Left,
            WHAT_DO_YOU_THINK_NIGHTMARE_DOG);

        outline_print(&mut app, &Aabb2::new(Point2::new(260.0f32, 0.0f32), Point2::new(380.0f32, 16.0f32)),
            &consts::CORNFLOWERBLUE, Center,
            "Focus object");

        outline_print(&mut app, &Aabb2::new(Point2::new(560.0f32, 0.0f32), Point2::new(640.0f32, 16.0f32)),
            &consts::LIGHTSLATEGRAY, Right,
            "Area Name");

        app.flush();
    }
}
<commit_msg>Keyboard support in shiny demo<commit_after>extern crate cgmath;
extern crate color;
extern crate glutil;
extern crate calx;

use std::cmp::max;
use glutil::app::App;
use glutil::app;
use glutil::key;
use cgmath::aabb::{Aabb, Aabb2};
use cgmath::point::{Point, Point2};
use cgmath::vector::{Vec2};
use color::rgb::{ToRGB, consts};
use calx::rectutil::RectUtil;

static WHAT_DO_YOU_THINK_NIGHTMARE_DOG: &'static str =
"This is of no consequence, the new Tower of Babel nears completion. All \
humanity will be made whole again, a nightmare god of flesh and bone, singing \
one chorus with its million mouths.";

enum Align {
    Left,
    Center,
    Right
}

fn print_words<C: ToRGB>(
    app: &mut App, area: &Aabb2<f32>, color: &C, align: Align, text: &str) {
    let words: ~[&str] = text.split(' ').collect();
    let bounds = words.map(|&w| app.string_bounds(w).dim().x as uint);
    let mut i = 0;
    let origin = area.min().add_v(&Vec2::new(0.0, app::FONT_HEIGHT)).to_vec();
    let width = area.dim().x;
    let max_lines = (area.dim().y / app::FONT_HEIGHT) as uint;
    let mut pos = origin;
    let mut line = 0;
    while i < words.len() && line < max_lines {
        let (n, len) = num_fitting_words(width as uint, app::FONT_SPACE as uint, bounds.slice(i, bounds.len()));
        let n = max(1, n);

        let diff = area.dim().x - len as f32;
        match align {
            Left => (),
            Center => { pos.x += diff / 2.0; },
            Right => { pos.x += diff; },
        }
        for j in range(i, i + n) {
            app.draw_string(&pos, color, words[j]);
            pos.x += bounds[j] as f32 + app::FONT_SPACE;
        }
        i += n;
        pos.x = origin.x;
        pos.y += app::FONT_HEIGHT;
        line += 1;
    }

    fn num_fitting_words(span: uint, space: uint, lengths: &[uint]) -> (uint, uint) {
        if lengths.len() == 0 { return (0, 0) }
        let mut total = lengths[0];
        for i in range(1, lengths.len()) {
            let new_total = total + space + lengths[i];
            if new_total > span {
                return (i, total);
            }
            total = new_total;
        }
        return (lengths.len(), total);
    }
}

fn outline_print<C: ToRGB>(
    app: &mut App, area: &Aabb2<f32>, color: &C, align: Align, text: &str) {
    print_words(app, &area.add_v(&Vec2::new(-1.0f32, 1.0f32)), &consts::BLACK, align, text);
    print_words(app, area, color, align, text);
}

pub fn main() {
    let mut app = App::new(640, 360, "Shiny!");

    while app.alive {
        app.fill_rect(&RectUtil::new(0.0f32, 0.0f32, 640.0f32, 360.0f32), &consts::MIDNIGHTBLUE);

        let text_zone = Aabb2::new(Point2::new(4.0f32, 200.0f32), Point2::new(240.0f32, 360.0f32));
        outline_print(&mut app, &text_zone,
            &consts::LIGHTSLATEGRAY, Left,
            WHAT_DO_YOU_THINK_NIGHTMARE_DOG);

        outline_print(&mut app, &Aabb2::new(Point2::new(260.0f32, 0.0f32), Point2::new(380.0f32, 16.0f32)),
            &consts::CORNFLOWERBLUE, Center,
            "Focus object");

        outline_print(&mut app, &Aabb2::new(Point2::new(560.0f32, 0.0f32), Point2::new(640.0f32, 16.0f32)),
            &consts::LIGHTSLATEGRAY, Right,
            "Area Name");

        for key in app.key_buffer().iter() {
            if key.code == key::ESC {
                return;
            }

            if key.code == key::F12 {
                app.screenshot("/tmp/shot.png");
            }
        }

        app.flush();
    }
}
<|endoftext|>


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

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::{CFURL, CFURLRef};
use core_graphics::base::CGFloat;

use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = (1 << 13);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumberRef,CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
struct __CTFontDescriptor;

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

#[derive(Debug)]
pub struct CTFontDescriptor {
    obj: CTFontDescriptorRef,
}

impl Drop for CTFontDescriptor {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl TCFType<CTFontDescriptorRef> for CTFontDescriptor {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CTFontDescriptorRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CTFontDescriptorRef) -> CTFontDescriptor {
        let reference: CTFontDescriptorRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CTFontDescriptorGetTypeID()
        }
    }
}

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFStringRef,CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font2 must have a non-null font family name.")
    }

    pub fn font_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontNameAttribute);
        value.expect("A font must have a non-null name.")
    }

    pub fn style_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontStyleNameAttribute);
        value.expect("A font must have a non-null style name.")
    }

    pub fn display_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font must have a non-null display name.")
    }

    pub fn font_path(&self) -> String {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURLRef,CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            format!("{:?}", url)
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<commit_msg>Auto merge of #58 - algesten:font_path, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::{CFURL, CFURLRef};
use core_graphics::base::CGFloat;

use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = (1 << 13);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumberRef,CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
struct __CTFontDescriptor;

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

#[derive(Debug)]
pub struct CTFontDescriptor {
    obj: CTFontDescriptorRef,
}

impl Drop for CTFontDescriptor {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl TCFType<CTFontDescriptorRef> for CTFontDescriptor {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CTFontDescriptorRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CTFontDescriptorRef) -> CTFontDescriptor {
        let reference: CTFontDescriptorRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CTFontDescriptorGetTypeID()
        }
    }
}

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFStringRef,CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font2 must have a non-null font family name.")
    }

    pub fn font_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontNameAttribute);
        value.expect("A font must have a non-null name.")
    }

    pub fn style_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontStyleNameAttribute);
        value.expect("A font must have a non-null style name.")
    }

    pub fn display_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font must have a non-null display name.")
    }

    pub fn font_path(&self) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontURLAttribute);
            if (value.is_null()) {
                return None;
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURLRef,CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(format!("{:?}", url))
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {:?}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<|endoftext|>


<commit_before>pub trait Monoid {
    static pure fn mempty() -> self;
    pure fn mappend(&&other: self) -> self;
}

pub struct Sum<T> { repr: T }
pub pure fn Sum<T>(val: T) -> Sum<T> { Sum { repr: val } }

impl<T: Num> Sum<T> : Monoid {
    static pure fn mempty() -> Sum<T> { Sum(num::from_int(0)) }
    pure fn mappend(&&other: Sum<T>) -> Sum<T> { Sum(self.repr.add(other.repr)) }
}

impl<T: cmp::Eq> Sum<T> : cmp::Eq {
    pure fn eq(other: &Sum<T>) -> bool { self.repr == other.repr }
    pure fn ne(other: &Sum<T>) -> bool { self.repr != other.repr }
}

pub struct Prod<T> { repr: T }
pub pure fn Prod<T>(val: T) -> Prod<T> { Prod { repr: val }}

impl <T: Num> Prod<T>: Monoid {
    static pure fn mempty() -> Prod<T> { Prod(num::from_int(1)) }
    pure fn mappend(&&other: Prod<T>) -> Prod<T> { Prod(self.repr.mul(other.repr)) }
}

impl<T: cmp::Eq> Prod<T> : cmp::Eq {
    pure fn eq(other: &Prod<T>) -> bool { self.repr == other.repr }
    pure fn ne(other: &Prod<T>) -> bool { self.repr != other.repr }
}

pub fn mconcat<T: Copy Monoid>(v: &[T]) -> T {
    vec::foldl(mempty(), v, |accum, elt| { elt.mappend(accum) })
}

pub fn merge<T: Copy cmp::Ord, M: Copy Monoid>(vec1: &[(T, M)], vec2: &[(T, M)]) -> ~[(T, M)] {
    let mut result = ~[];
    let mut (itr1, itr2) = (vec1, vec2);
    while (itr1.is_not_empty() && itr2.is_not_empty()) {
        let ((v1, m1), (v2, m2)) = (itr1.head(), itr2.head());
        if v1 < v2 {
            vec::push(result, (v1, m1));
            itr1 = vec::view(itr1, 1u, itr1.len());
            loop;
        }
        if v2 < v1 {
            vec::push(result, (v2, m2));
            itr2 = vec::view(itr2, 1u, itr2.len());
            loop;
        }
        vec::push(result, (v1, m1.mappend(m2)));
        itr1 = vec::view(itr1, 1u, itr1.len());
        itr2 = vec::view(itr2, 1u, itr2.len());
    }

    if itr1.is_not_empty() { result += itr1; }
    if itr2.is_not_empty() { result += itr2; }
    return result;
}

pub fn mergei<T: Copy cmp::Ord, M: Copy Monoid>(vecs: &[~[(T, M)]]) -> ~[(T, M)] {
    return match vecs.len() {
      0u => ~[],
      1u => ~[] + vecs[0],
      len  => {
        let pre  = mergei(vec::view(vecs, 0u, len / 2u));
        let post = mergei(vec::view(vecs, len / 2u, len));
        merge(pre, post)
      }
    }
}

#[cfg(test)]
mod tests {
    fn to_sum<T: Copy, U: Copy Num>(tp: &(T, U)) -> (T, Sum<U>) {
        let (t, u) = *tp;
        return (t, Sum(u));
    }

    struct Max<T> { repr: T }
    pure fn Max<T>(val: T) -> Max<T> { Max { repr: val } }
    impl <T: Copy cmp::Ord Num> Max<T>: Monoid {
        static pure fn mempty() -> Max<T> {
            let neg_max = num::from_int::<T>(int::min_value);
            let zero    = num::from_int(0);
            if neg_max < zero {
                Max::<T>(neg_max)
            } else {
                Max::<T>(zero)
            }
        }
        pure fn mappend(&&other: Max<T>) -> Max<T> { if self.repr < other.repr { other } else { self } }
    }
    impl <T: cmp::Eq> Max<T>: cmp::Eq {
        pure fn eq(other: &Max<T>) -> bool { self.repr == other.repr }
        pure fn ne(other: &Max<T>) -> bool { self.repr != other.repr }
    }
    fn to_max<T: Copy, U: Copy cmp::Ord>(tp: &(T, U)) -> (T, Max<U>) {
        let (t, u) = *tp;
        return (t, Max(u));
    }

    #[test]
    fn test_merge() {
        let arg1 = [(1, 1), (3, 1), (4, 1), (6, 1)];
        let arg2 = [(1, 2), (2, 1), (4, 1), (7, 2)];

        {
            let result = [(1, 3), (2, 1), (3, 1), (4, 2), (6, 1), (7, 2)].map(to_sum);
            assert merge(arg1.map(to_sum), arg2.map(to_sum)) == result;
        }

        {
            let result = [(1, 2), (2, 1), (3, 1), (4, 1), (6, 1), (7, 2)].map(to_max);
            assert merge(arg1.map(to_max), arg2.map(to_max)) == result;
        }

        {
            let result = arg1.map(to_sum);
            assert merge(result, []) == result;
        }

        {
            let result: ~[(int, Sum<int>)] = ~[];
            assert merge([], []) == result;
        }
    }

    #[test]
    fn test_mergei() {
        {
            let arg = [~[to_sum(&(1, 1)), to_sum(&(2, 1))], ~[to_sum(&(1, 2)), to_sum(&(3, 1))], ~[to_sum(&(-1, 3))]];
            let result = [(-1, 3), (1, 3), (2, 1), (3, 1)].map(to_sum);
            assert mergei(arg) == result;
        }

        {
            let arg = [~[to_sum(&(1, 1))], ~[to_sum(&(1, 2))], ~[to_sum(&(1, 3))]];
            let result: ~[(int, Sum<int>)] = ~[to_sum(&(1, 6))];
            assert mergei(arg) == result;
        }

        {
            let result: ~[(int, Sum<int>)] = ~[];
            assert mergei([~[], ~[], ~[]]) == result;
        }
    }
}

<commit_msg>De-mode Monoid<commit_after>pub trait Monoid {
    static pure fn mempty() -> self;
    pure fn mappend(other: &self) -> self;
}

pub struct Sum<T> { repr: T }
pub pure fn Sum<T>(val: T) -> Sum<T> { Sum { repr: val } }

impl<T: Num> Sum<T> : Monoid {
    static pure fn mempty() -> Sum<T> { Sum(num::from_int(0)) }
    pure fn mappend(other: &Sum<T>) -> Sum<T> { Sum(self.repr.add(other.repr)) }
}

impl<T: cmp::Eq> Sum<T> : cmp::Eq {
    pure fn eq(other: &Sum<T>) -> bool { self.repr == other.repr }
    pure fn ne(other: &Sum<T>) -> bool { self.repr != other.repr }
}

pub struct Prod<T> { repr: T }
pub pure fn Prod<T>(val: T) -> Prod<T> { Prod { repr: val }}

impl <T: Num> Prod<T>: Monoid {
    static pure fn mempty() -> Prod<T> { Prod(num::from_int(1)) }
    pure fn mappend(other: &Prod<T>) -> Prod<T> { Prod(self.repr.mul(other.repr)) }
}

impl<T: cmp::Eq> Prod<T> : cmp::Eq {
    pure fn eq(other: &Prod<T>) -> bool { self.repr == other.repr }
    pure fn ne(other: &Prod<T>) -> bool { self.repr != other.repr }
}

pub fn mconcat<T: Copy Monoid>(v: &[T]) -> T {
    vec::foldl(mempty(), v, |accum, elt| { elt.mappend(&accum) })
}

pub fn merge<T: Copy cmp::Ord, M: Copy Monoid>(vec1: &[(T, M)], vec2: &[(T, M)]) -> ~[(T, M)] {
    let mut result = ~[];
    let mut (itr1, itr2) = (vec1, vec2);
    while (itr1.is_not_empty() && itr2.is_not_empty()) {
        let ((v1, m1), (v2, m2)) = (itr1.head(), itr2.head());
        if v1 < v2 {
            vec::push(result, (v1, m1));
            itr1 = vec::view(itr1, 1u, itr1.len());
            loop;
        }
        if v2 < v1 {
            vec::push(result, (v2, m2));
            itr2 = vec::view(itr2, 1u, itr2.len());
            loop;
        }
        vec::push(result, (v1, m1.mappend(&m2)));
        itr1 = vec::view(itr1, 1u, itr1.len());
        itr2 = vec::view(itr2, 1u, itr2.len());
    }

    if itr1.is_not_empty() { result += itr1; }
    if itr2.is_not_empty() { result += itr2; }
    return result;
}

pub fn mergei<T: Copy cmp::Ord, M: Copy Monoid>(vecs: &[~[(T, M)]]) -> ~[(T, M)] {
    return match vecs.len() {
      0u => ~[],
      1u => ~[] + vecs[0],
      len  => {
        let pre  = mergei(vec::view(vecs, 0u, len / 2u));
        let post = mergei(vec::view(vecs, len / 2u, len));
        merge(pre, post)
      }
    }
}

#[cfg(test)]
mod tests {
    fn to_sum<T: Copy, U: Copy Num>(tp: &(T, U)) -> (T, Sum<U>) {
        let (t, u) = *tp;
        return (t, Sum(u));
    }

    struct Max<T> { repr: T }
    pure fn Max<T>(val: T) -> Max<T> { Max { repr: val } }
    impl <T: Copy cmp::Ord Num> Max<T>: Monoid {
        static pure fn mempty() -> Max<T> {
            let neg_max = num::from_int::<T>(int::min_value);
            let zero    = num::from_int(0);
            if neg_max < zero {
                Max::<T>(neg_max)
            } else {
                Max::<T>(zero)
            }
        }
        pure fn mappend(other: &Max<T>) -> Max<T> { if self.repr < other.repr { *other } else { self } }
    }
    impl <T: cmp::Eq> Max<T>: cmp::Eq {
        pure fn eq(other: &Max<T>) -> bool { self.repr == other.repr }
        pure fn ne(other: &Max<T>) -> bool { self.repr != other.repr }
    }
    fn to_max<T: Copy, U: Copy cmp::Ord>(tp: &(T, U)) -> (T, Max<U>) {
        let (t, u) = *tp;
        return (t, Max(u));
    }

    #[test]
    fn test_merge() {
        let arg1 = [(1, 1), (3, 1), (4, 1), (6, 1)];
        let arg2 = [(1, 2), (2, 1), (4, 1), (7, 2)];

        {
            let result = [(1, 3), (2, 1), (3, 1), (4, 2), (6, 1), (7, 2)].map(to_sum);
            assert merge(arg1.map(to_sum), arg2.map(to_sum)) == result;
        }

        {
            let result = [(1, 2), (2, 1), (3, 1), (4, 1), (6, 1), (7, 2)].map(to_max);
            assert merge(arg1.map(to_max), arg2.map(to_max)) == result;
        }

        {
            let result = arg1.map(to_sum);
            assert merge(result, []) == result;
        }

        {
            let result: ~[(int, Sum<int>)] = ~[];
            assert merge([], []) == result;
        }
    }

    #[test]
    fn test_mergei() {
        {
            let arg = [~[to_sum(&(1, 1)), to_sum(&(2, 1))], ~[to_sum(&(1, 2)), to_sum(&(3, 1))], ~[to_sum(&(-1, 3))]];
            let result = [(-1, 3), (1, 3), (2, 1), (3, 1)].map(to_sum);
            assert mergei(arg) == result;
        }

        {
            let arg = [~[to_sum(&(1, 1))], ~[to_sum(&(1, 2))], ~[to_sum(&(1, 3))]];
            let result: ~[(int, Sum<int>)] = ~[to_sum(&(1, 6))];
            assert mergei(arg) == result;
        }

        {
            let result: ~[(int, Sum<int>)] = ~[];
            assert mergei([~[], ~[], ~[]]) == result;
        }
    }
}

<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::collections::hash_map::HashMap;
use std::fmt::{self, Debug};
use std::hash::Hash;

// TODO: Consider using BTreeMap, possible perforance increase. Do benchmarks.
/// A stack of scopes of something. Fast access due to hashmaps, and guaranteed to contain no
/// duplications at any point.
///
/// Used for ConstDef:s. Only one constant can be defined for a single name at any given moment.
#[derive(Clone)]
pub struct ScopeStack<K, V>(Vec<HashMap<K, V>>);

impl<K: Hash + Eq, V> ScopeStack<K, V> {
    pub fn new() -> ScopeStack<K, V> {
        ScopeStack(Vec::new())
    }

    pub fn push(&mut self, scope: HashMap<K, V>) {
        if scope.keys().any(|key| self.contains_key(key)) {
            panic!("ScopeStack::push: Key already exists");
        }
        self.0.push(scope);
    }

    pub fn pop(&mut self) -> Option<HashMap<K, V>> {
        self.0.pop()
    }

    pub fn split_off(&mut self, at: usize) -> Vec<HashMap<K, V>> {
        self.0.split_off(at)
    }

    pub fn extend(&mut self, xs: Vec<HashMap<K, V>>) {
        self.0.extend(xs)
    }

    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        self.0.iter().any(|scope| scope.contains_key(key))
    }

    pub fn get_height<Q: ?Sized>(&self, key: &Q) -> Option<usize>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter().enumerate() {
            if scope.contains_key(key) {
                return Some(height);
            }
        }
        None
    }

    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        self.get_with_height(key).map(|(v, _)| v)
    }

    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        self.get_mut_with_height(key).map(|(v, _)| v)
    }

    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        for scope in self.0.iter_mut().rev() {
            if let Some(def) = scope.remove(key) {
                return Some(def);
            }
        }
        None
    }

    pub fn get_with_height<Q: ?Sized>(&self, key: &Q) -> Option<(&V, usize)>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter().enumerate().rev() {
            if let Some(def) = scope.get(key) {
                return Some((def, height));
            }
        }
        None
    }

    pub fn get_mut_with_height<Q: ?Sized>(&mut self, key: &Q) -> Option<(&mut V, usize)>
    where
        Q: Hash + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter_mut().enumerate().rev() {
            if let Some(def) = scope.get_mut(key) {
                return Some((def, height));
            }
        }
        None
    }
}

impl<K: Debug + Hash + Eq, V: Debug> Debug for ScopeStack<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

struct AddMapNode<K, V> {
    key: K,
    val: V,
    /// null indicates no next node
    next: *mut Option<AddMapNode<K, V>>,
}

impl<K, V> AddMapNode<K, V> {
    fn entry<'a, Q>(&'a self, key: &Q) -> Option<(&'a K, &'a V)>
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        if &self.key == key {
            Some((&self.key, &self.val))
        } else {
            unsafe { (*self.next).as_ref().and_then(|n| n.entry(key)) }
        }
    }

    fn add(&self, key: K, val: V) -> (&K, &V)
    where
        K: PartialEq<K>,
    {
        if self.key == key {
            panic!("Key already exists in map")
        } else {
            unsafe {
                match *self.next {
                    None => {
                        *self.next = Some(AddMapNode {
                            key: key,
                            val: val,
                            next: Box::into_raw(Box::new(None)),
                        });
                        let next = (*self.next).as_ref().unwrap();
                        (&next.key, &next.val)
                    }
                    Some(ref next_node) => next_node.add(key, val),
                }
            }
        }
    }
}

/// A map which can only grow.
///
/// Implemented with a linked list
pub struct AddMap<K, V> {
    next: *mut Option<AddMapNode<K, V>>,
}

impl<K, V> AddMap<K, V>
where
    K: PartialEq<K>,
{
    pub fn new() -> Self {
        AddMap { next: Box::into_raw(Box::new(None)) }
    }

    /// Get reference to key and value in map associated with `key`
    ///
    /// Executes in `O(n)` time
    pub fn entry<Q>(&self, key: &Q) -> Option<(&K, &V)>
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        unsafe { (*self.next).as_ref().and_then(|n| n.entry(key)) }
    }

    /// Returns whether the map contains `key`
    pub fn contains_key<Q>(&self, key: &Q) -> bool
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        self.entry(key).is_some()
    }

    /// Insert the value `val` with key `key` in map
    ///
    /// Returns reference to entry in map.
    /// Executes in `O(n)` time
    ///
    /// # Panics
    ///
    /// Panics if `key` already exists in list
    pub fn add(&self, key: K, val: V) -> (&K, &V) {
        unsafe {
            if (*self.next).is_none() {
                *self.next = Some(AddMapNode {
                    key: key,
                    val: val,
                    next: Box::into_raw(Box::new(None)),
                });
                let next = (*self.next).as_ref().unwrap();
                (&next.key, &next.val)
            } else {
                (*self.next).as_ref().unwrap().add(key, val)
            }
        }
    }
}
<commit_msg>Use BTreeMap in collections<commit_after>use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

// TODO: Consider using BTreeMap, possible perforance increase. Do benchmarks.
/// A stack of scopes of something. Fast access due to hashmaps, and guaranteed to contain no
/// duplications at any point.
///
/// Used for ConstDef:s. Only one constant can be defined for a single name at any given moment.
#[derive(Clone)]
pub struct ScopeStack<K, V>(Vec<BTreeMap<K, V>>);

impl<K: Ord + Eq, V> ScopeStack<K, V> {
    pub fn new() -> ScopeStack<K, V> {
        ScopeStack(Vec::new())
    }

    pub fn push(&mut self, scope: BTreeMap<K, V>) {
        if scope.keys().any(|key| self.contains_key(key)) {
            panic!("ScopeStack::push: Key already exists");
        }
        self.0.push(scope);
    }

    pub fn pop(&mut self) -> Option<BTreeMap<K, V>> {
        self.0.pop()
    }

    pub fn split_off(&mut self, at: usize) -> Vec<BTreeMap<K, V>> {
        self.0.split_off(at)
    }

    pub fn extend(&mut self, xs: Vec<BTreeMap<K, V>>) {
        self.0.extend(xs)
    }

    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        self.0.iter().any(|scope| scope.contains_key(key))
    }

    pub fn get_height<Q: ?Sized>(&self, key: &Q) -> Option<usize>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter().enumerate() {
            if scope.contains_key(key) {
                return Some(height);
            }
        }
        None
    }

    pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        self.get_with_height(key).map(|(v, _)| v)
    }

    pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        self.get_mut_with_height(key).map(|(v, _)| v)
    }

    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        for scope in self.0.iter_mut().rev() {
            if let Some(def) = scope.remove(key) {
                return Some(def);
            }
        }
        None
    }

    pub fn get_with_height<Q: ?Sized>(&self, key: &Q) -> Option<(&V, usize)>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter().enumerate().rev() {
            if let Some(def) = scope.get(key) {
                return Some((def, height));
            }
        }
        None
    }

    pub fn get_mut_with_height<Q: ?Sized>(&mut self, key: &Q) -> Option<(&mut V, usize)>
    where
        Q: Ord + Eq,
        K: Borrow<Q>,
    {
        for (height, scope) in self.0.iter_mut().enumerate().rev() {
            if let Some(def) = scope.get_mut(key) {
                return Some((def, height));
            }
        }
        None
    }
}

impl<K: Debug + Ord + Eq, V: Debug> Debug for ScopeStack<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

struct AddMapNode<K, V> {
    key: K,
    val: V,
    /// null indicates no next node
    next: *mut Option<AddMapNode<K, V>>,
}

impl<K, V> AddMapNode<K, V> {
    fn entry<'a, Q>(&'a self, key: &Q) -> Option<(&'a K, &'a V)>
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        if &self.key == key {
            Some((&self.key, &self.val))
        } else {
            unsafe { (*self.next).as_ref().and_then(|n| n.entry(key)) }
        }
    }

    fn add(&self, key: K, val: V) -> (&K, &V)
    where
        K: PartialEq<K>,
    {
        if self.key == key {
            panic!("Key already exists in map")
        } else {
            unsafe {
                match *self.next {
                    None => {
                        *self.next = Some(AddMapNode {
                            key: key,
                            val: val,
                            next: Box::into_raw(Box::new(None)),
                        });
                        let next = (*self.next).as_ref().unwrap();
                        (&next.key, &next.val)
                    }
                    Some(ref next_node) => next_node.add(key, val),
                }
            }
        }
    }
}

/// A map which can only grow.
///
/// Implemented with a linked list
pub struct AddMap<K, V> {
    next: *mut Option<AddMapNode<K, V>>,
}

impl<K, V> AddMap<K, V>
where
    K: PartialEq<K>,
{
    pub fn new() -> Self {
        AddMap {
            next: Box::into_raw(Box::new(None)),
        }
    }

    /// Get reference to key and value in map associated with `key`
    ///
    /// Executes in `O(n)` time
    pub fn entry<Q>(&self, key: &Q) -> Option<(&K, &V)>
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        unsafe { (*self.next).as_ref().and_then(|n| n.entry(key)) }
    }

    /// Returns whether the map contains `key`
    pub fn contains_key<Q>(&self, key: &Q) -> bool
    where
        K: Borrow<Q> + PartialEq<Q>,
    {
        self.entry(key).is_some()
    }

    /// Insert the value `val` with key `key` in map
    ///
    /// Returns reference to entry in map.
    /// Executes in `O(n)` time
    ///
    /// # Panics
    ///
    /// Panics if `key` already exists in list
    pub fn add(&self, key: K, val: V) -> (&K, &V) {
        unsafe {
            if (*self.next).is_none() {
                *self.next = Some(AddMapNode {
                    key: key,
                    val: val,
                    next: Box::into_raw(Box::new(None)),
                });
                let next = (*self.next).as_ref().unwrap();
                (&next.key, &next.val)
            } else {
                (*self.next).as_ref().unwrap().add(key, val)
            }
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("hello");
}
<commit_msg>rust 1. Hello World<commit_after>use std::fmt::{self, Formatter, Display};

fn main() {
    println!("Hello World!");

    let x = 5 + /* 90 + */ 5;
    println!("Is `x` 10 or 100? x = {}", x);

    // 1.2
    println!("{} days", 31);

    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
    println!("{subject} {verb} {predicate}",
             predicate="over the lazy dog",
             subject="the quick brown fox",
             verb="jumps");
    println!("{} of {:b} people know binary", 1, 2);
    println!("{number:>width$}", number=1, width=6);
    println!("{number:>0width$}", number=1, width=6);

    // println!("My name is {0}, {1} {0}", "Bond");
    // <std macros>:3:11: 3:36 error: invalid reference to argument `1` (there is 1 argument)

    //struct Structure(i32);
    // println!("This struct `{}` won't print...", Structure(3));
    // hello.rs:22:49: 22:61 error: the trait `core::fmt::Display` is not implemented for the type `main::Structure` [E0277]

    #[allow(dead_code)]
    struct UnPrintable(i32);
    #[derive(Debug)]
    struct Structure(i32);
    #[derive(Debug)]
    struct Deep(Structure);

    // 1.2.1
    println!("{:?} months in a year.", 12);
    println!("{1:?} {0:?} is the {actor:?} name",
             "Slater", "Christian", actor="actor's");
    println!("Now {:?} will print!", Structure(3));
    println!("Now {:?} will print!", Deep(Structure(7)));

    // 1.2.2
    // need to implement Display to use '{}' marker.
    impl fmt::Display for Structure {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.0)
        }
    }
    println!("Now {} will print!", Structure(12));

    #[derive(Debug)]
    struct MinMax(i64, i64);
    impl fmt::Display for MinMax {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "({}, {})", self.0, self.1)
        }
    }
    #[derive(Debug)]
    struct Point2 {
        x: f64,
        y: f64,
    }
    impl fmt::Display for Point2 {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "x: {}, y: {}", self.x, self.y)
        }
    }

    let minmax = MinMax(0, 14);
    println!("Compare structures:");
    println!("Display: {}", minmax);
    println!("Debug: {:?}", minmax);

    let big_range = MinMax(-300, 300);
    let small_range = MinMax(-3, 3);
    println!("The big range is {big} and the small is {small}",
             small = small_range, big = big_range);

    let point = Point2 { x: 3.3, y: 7.2 };
    println!("Compare points:");
    println!("Display: {}", point);
    println!("Debug: {:?}", point);
    // hello.rs:79:30: 79:35 error: the trait `core::fmt::Binary` is not implemented for the type `main::Point2` [E0277]
    // println!("Binary: {:b}", point);

    // 1.2.2.1
    struct List(Vec<i32>);
    impl fmt::Display for List {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let List(ref vec) = *self;
            try!(write!(f, "["));
            for (count, v) in vec.iter().enumerate() {
                if count != 0 { try!(write!(f, ", ")); }
                try!(write!(f, "{}", v));
            }
            write!(f, "]")
        }
    }
    let v = List(vec![1,2,3]);
    println!("{}", v);

    // 1.2.3
    struct City {
        name: &'static str,
        lat: f32,
        lon: f32,
    }
    impl fmt::Display for City {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
            let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };
            write!(f, "{}: {:.3}°{} {:.3}°{}", self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)
        }
    }
    #[derive(Debug)]
    struct Color {
        red: u8,
        green: u8,
        blue: u8,
    }
    for city in [
        City { name: "Dublin", lat: 53.347778, lon: -6.259722 },
        City { name: "Oslo", lat: 59.95, lon: 10.75 },
        City { name: "Vancouver", lat: 49.25, lon: -123.1 },
    ].iter() {
        println!("{}", *city);
    }
    for color in [
        Color { red: 128, green: 255, blue: 90 },
        Color { red: 0, green: 3, blue: 254 },
        Color { red: 0, green: 0, blue: 0 },
    ].iter() {
        println!("{:?}", *color);
    }
}
<|endoftext|>