<commit_before>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett
// rust-monster is licensed under a MIT License.

//! Genetic Algorithm Population

use super::ga_core::GASolution;

use std::cmp::Ordering;
use std::iter::FromIterator;

// Better name than 'Basis'?
#[derive(Clone, Copy)]
pub enum GAPopulationSortBasis
{
    Raw,
    Scaled,
}

// The 'Copy' trait requires the 'Clone' trait.
// 'Copy' removes the 'move' semantics from an assignment or a function return of value.
#[derive(Clone, Copy)]
pub enum GAPopulationSortOrder
{
    LowIsBest,
    HighIsBest,
}

/// Genetic Algorithm Population
pub struct GAPopulation<T: GASolution>
{
    population: Vec<T>,

    sort_order: GAPopulationSortOrder,

    // 'population' ordered by Raw score.
    population_order_raw: Vec<usize>,
    // Is 'population_order_raw' sorted?
    is_raw_sorted: bool,

    // 'population' ordered by Scaled score.
    population_order_scaled: Vec<usize>,
    // Is 'population_scaled' sorted?
    is_scaled_sorted: bool,

    // We keep 2 lists of indexes to the population vector.
    // One sorted by Raw Score and one by Scaled Score (Fitness).
}
impl<T: GASolution> GAPopulation<T>
{
    // TODO: New should use some parameters, maybe a Config
    pub fn new(p: Vec<T>, order: GAPopulationSortOrder) -> GAPopulation<T>
    {
        let gap = GAPopulation
                  {
                      population: p,
                      sort_order: order,
                      population_order_raw: vec![],
                      is_raw_sorted: false,
                      population_order_scaled: vec![],
                      is_scaled_sorted: false
                  };

        gap
    }

    pub fn population(&mut self) -> &mut Vec<T>
    {
        return &mut self.population
    }

    pub fn evaluate(&mut self)
    {
        for ref mut ind in &mut self.population
        {
            ind.evaluate();
        }
    }

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

    pub fn order(&self) -> GAPopulationSortOrder
    {
        // This is not a 'move', but a copy (GAPopulationSortOrder implements the
        // 'Copy' trait). A move from a borrowed reference (such as 'self') would
        // not be permitted.
        self.sort_order
    }

    //TODO: this is a temporary implementation
    pub fn select(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn best(&self) -> &T
    {
        // TODO: Call GAPopulation.scale().

        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn worst(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_raw_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_raw_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_scaled_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_scaled_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn individual(&self, i : usize, sort_basis : GAPopulationSortBasis) -> &T
    {
        // TODO: Check that i makes sense
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            => { &self.population[self.population_order_raw[i]] },
            GAPopulationSortBasis::Scaled
            => { &self.population[self.population_order_scaled[i]] },
        }
    }

    pub fn sort(&mut self)
    {
        self.sort_int(false, GAPopulationSortBasis::Scaled);
        self.sort_int(false, GAPopulationSortBasis::Raw);
    }

    //TODO: I hate this name
    pub fn sort_int(&mut self, force_sort: bool, sort_basis: GAPopulationSortBasis)
    {
        let mut ordered : Vec<usize> = Vec::from_iter(0..self.size());
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            =>  if (!self.is_raw_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].score()
                                                .partial_cmp(&self.population[*s2].score()).unwrap_or(Ordering::Equal));

                        },
                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].score()
                                                .partial_cmp(&self.population[*s1].score()).unwrap_or(Ordering::Equal));

                        },
                    };
                    self.population_order_raw = ordered;
                    self.is_raw_sorted = true;
                },

            GAPopulationSortBasis::Scaled
            =>  if (!self.is_scaled_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].fitness()
                                                .partial_cmp(&self.population[*s2].fitness()).unwrap_or(Ordering::Equal));
                        },

                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].fitness()
                                                .partial_cmp(&self.population[*s1].fitness()).unwrap_or(Ordering::Equal));
                        }
                    };
                    self.population_order_scaled = ordered;
                    self.is_scaled_sorted = true;
                },
        };
    }

    pub fn raw_score_iterator<'a>(&'a self) -> GAPopulationRawIterator<'a, T>
    {
        GAPopulationRawIterator { population: &self, next: 0 }
    }

    pub fn fitness_score_iterator<'a>(&'a self) -> GAPopulationFitnessIterator<'a, T>
    {
        GAPopulationFitnessIterator { population: &self, next: 0 }
    }
}

pub struct GAPopulationRawIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationRawIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next == self.population.size()
        {
            None
        }
        else
        {
            self.next = self.next + 1;
            Some(self.population.individual(self.next - 1, GAPopulationSortBasis::Raw))
        }
    }
}

pub struct GAPopulationFitnessIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next: usize
}

impl<'a, T: 'a + GASolution> Iterator for GAPopulationFitnessIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next == self.population.size()
        {
            None
        }
        else
        {
            self.next = self.next + 1;
            Some(self.population.individual(self.next - 1, GAPopulationSortBasis::Scaled))
        }
    }

}

////////////////////////////////////////
// Tests
#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_test::*;
    use super::super::ga_core::*;

    #[test]
    fn test_sort_population()
    {
        ga_test_setup("ga_population::test_sort_population");
        let f = GA_TEST_FITNESS_VAL;
        let f_m = GA_TEST_FITNESS_VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![GATestSolution::new(f), GATestSolution::new(f_m)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //GATestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
        ga_test_teardown();
    }

}
<commit_msg>Remove redundant lifetime bound of GASolution in Iterator trait impls.<commit_after>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett
// rust-monster is licensed under a MIT License.

//! Genetic Algorithm Population

use super::ga_core::GASolution;

use std::cmp::Ordering;
use std::iter::FromIterator;

// Better name than 'Basis'?
#[derive(Clone, Copy)]
pub enum GAPopulationSortBasis
{
    Raw,
    Scaled,
}

// The 'Copy' trait requires the 'Clone' trait.
// 'Copy' removes the 'move' semantics from an assignment or a function return of value.
#[derive(Clone, Copy)]
pub enum GAPopulationSortOrder
{
    LowIsBest,
    HighIsBest,
}

/// Genetic Algorithm Population
pub struct GAPopulation<T: GASolution>
{
    population: Vec<T>,

    sort_order: GAPopulationSortOrder,

    // 'population' ordered by Raw score.
    population_order_raw: Vec<usize>,
    // Is 'population_order_raw' sorted?
    is_raw_sorted: bool,

    // 'population' ordered by Scaled score.
    population_order_scaled: Vec<usize>,
    // Is 'population_scaled' sorted?
    is_scaled_sorted: bool,

    // We keep 2 lists of indexes to the population vector.
    // One sorted by Raw Score and one by Scaled Score (Fitness).
}
impl<T: GASolution> GAPopulation<T>
{
    // TODO: New should use some parameters, maybe a Config
    pub fn new(p: Vec<T>, order: GAPopulationSortOrder) -> GAPopulation<T>
    {
        let gap = GAPopulation
                  {
                      population: p,
                      sort_order: order,
                      population_order_raw: vec![],
                      is_raw_sorted: false,
                      population_order_scaled: vec![],
                      is_scaled_sorted: false
                  };

        gap
    }

    pub fn population(&mut self) -> &mut Vec<T>
    {
        return &mut self.population
    }

    pub fn evaluate(&mut self)
    {
        for ref mut ind in &mut self.population
        {
            ind.evaluate();
        }
    }

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

    pub fn order(&self) -> GAPopulationSortOrder
    {
        // This is not a 'move', but a copy (GAPopulationSortOrder implements the
        // 'Copy' trait). A move from a borrowed reference (such as 'self') would
        // not be permitted.
        self.sort_order
    }

    //TODO: this is a temporary implementation
    pub fn select(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn best(&self) -> &T
    {
        // TODO: Call GAPopulation.scale().

        self.individual(0, GAPopulationSortBasis::Scaled)
    }

    //TODO: This is a temporary implementation
    pub fn worst(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_raw_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_raw_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn best_by_scaled_score(&self) -> &T
    {
        self.individual(0, GAPopulationSortBasis::Raw)
    }

    pub fn worst_by_scaled_score(&self) -> &T
    {
        self.individual(self.size()-1, GAPopulationSortBasis::Scaled)
    }

    pub fn individual(&self, i : usize, sort_basis : GAPopulationSortBasis) -> &T
    {
        // TODO: Check that i makes sense
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            => { &self.population[self.population_order_raw[i]] },
            GAPopulationSortBasis::Scaled
            => { &self.population[self.population_order_scaled[i]] },
        }
    }

    pub fn sort(&mut self)
    {
        self.sort_int(false, GAPopulationSortBasis::Scaled);
        self.sort_int(false, GAPopulationSortBasis::Raw);
    }

    //TODO: I hate this name
    pub fn sort_int(&mut self, force_sort: bool, sort_basis: GAPopulationSortBasis)
    {
        let mut ordered : Vec<usize> = Vec::from_iter(0..self.size());
        match sort_basis
        {
            GAPopulationSortBasis::Raw
            =>  if (!self.is_raw_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].score()
                                                .partial_cmp(&self.population[*s2].score()).unwrap_or(Ordering::Equal));

                        },
                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].score()
                                                .partial_cmp(&self.population[*s1].score()).unwrap_or(Ordering::Equal));

                        },
                    };
                    self.population_order_raw = ordered;
                    self.is_raw_sorted = true;
                },

            GAPopulationSortBasis::Scaled
            =>  if (!self.is_scaled_sorted) || force_sort
                {
                    match self.sort_order
                    {
                        GAPopulationSortOrder::LowIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s1].fitness()
                                                .partial_cmp(&self.population[*s2].fitness()).unwrap_or(Ordering::Equal));
                        },

                        GAPopulationSortOrder::HighIsBest =>
                        {
                            ordered.sort_by(|s1: &usize, s2: &usize|
                                            self.population[*s2].fitness()
                                                .partial_cmp(&self.population[*s1].fitness()).unwrap_or(Ordering::Equal));
                        }
                    };
                    self.population_order_scaled = ordered;
                    self.is_scaled_sorted = true;
                },
        };
    }

    pub fn raw_score_iterator<'a>(&'a self) -> GAPopulationRawIterator<'a, T>
    {
        GAPopulationRawIterator { population: &self, next: 0 }
    }

    pub fn fitness_score_iterator<'a>(&'a self) -> GAPopulationFitnessIterator<'a, T>
    {
        GAPopulationFitnessIterator { population: &self, next: 0 }
    }
}

pub struct GAPopulationRawIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next: usize
}

impl<'a, T: GASolution> Iterator for GAPopulationRawIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next == self.population.size()
        {
            None
        }
        else
        {
            self.next = self.next + 1;
            Some(self.population.individual(self.next - 1, GAPopulationSortBasis::Raw))
        }
    }
}

pub struct GAPopulationFitnessIterator<'a, T: 'a + GASolution>
{
    population: &'a GAPopulation<T>,
    next: usize
}

impl<'a, T: GASolution> Iterator for GAPopulationFitnessIterator<'a, T>
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item>
    {
        if self.next == self.population.size()
        {
            None
        }
        else
        {
            self.next = self.next + 1;
            Some(self.population.individual(self.next - 1, GAPopulationSortBasis::Scaled))
        }
    }

}

////////////////////////////////////////
// Tests
#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_test::*;
    use super::super::ga_core::*;

    #[test]
    fn test_sort_population()
    {
        ga_test_setup("ga_population::test_sort_population");
        let f = GA_TEST_FITNESS_VAL;
        let f_m = GA_TEST_FITNESS_VAL - 1.0;
        let i_f = 1.0 / f;
        let i_f_m = 1.0 / f_m;

        let mut population = GAPopulation::new(vec![GATestSolution::new(f), GATestSolution::new(f_m)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        //GATestSolution's Fitness is the inverse of the Score (F = 1/S)
        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).score(), f);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Raw).score(), f_m);
        assert_eq!(population.individual(0, GAPopulationSortBasis::Scaled).fitness(), i_f_m);
        assert_eq!(population.individual(1, GAPopulationSortBasis::Scaled).fitness(), i_f);
        ga_test_teardown();
    }

}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

extern crate crowbook;
extern crate clap;

mod helpers;
use helpers::*;

use crowbook::{Book};
use clap::ArgMatches;
use std::process::exit;
use std::fs::File;
use std::io;

/// Render a book to specific format
fn render_format(book: &mut Book, matches: &ArgMatches, format: &str) -> ! {
    if let Some(file) = matches.value_of("output") {
        match format {
            "epub" => book.set_option("output.epub", file).unwrap(),
            "tex" => book.set_option("output.tex", file).unwrap(),
            "html" => book.set_option("output.html", file).unwrap(),
            "pdf" => book.set_option("output.pdf", file).unwrap(),
            "odt" => book.set_option("output.odt", file).unwrap(),
            _ => unreachable!()
        }
    }

    let option = match format {
        "epub" => book.get_str("output.epub"),
        "tex" => book.get_str("output.tex"),
        "html" => book.get_str("output.html"),
        "pdf" => book.get_str("output.pdf"),
        "odt" => book.get_str("output.odt"),
        _ => unreachable!()
    };
    let result = match option {
        Err(_) => {
            match format {
                "html" => book.render_html(&mut io::stdout()),
                "tex" => book.render_tex(&mut io::stdout()),
                _ => print_error(&format!("No output file specified, and book doesn't specify an output file for {}", format)),
            }
        },
        Ok(file) => {
            match format {
                "epub" => book.render_epub(),
                "tex" => {
                    let mut f = File::create(file).unwrap();
                    book.render_tex(&mut f)
                },
                "html" => {
                    let mut f = File::create(file).unwrap();
                    book.render_html(&mut f)
                },
                "pdf" => book.render_pdf(),
                "odt" => book.render_odt(),
                _ => unreachable!()
            }
        }
    };
    match result {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => {
                    println!("crowbook terminated successfully");
            exit(0);
        },
    }
}

fn main() {
    let matches = create_matches();

    if matches.is_present("list-options") {
        println!("{}", Book::description(false));
        exit(0);
    }

    if matches.is_present("list-options-md") {
        println!("{}", Book::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error(&format!("{} is not a valid template name.", template)),
        }
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error(&format!("You must pass the file of a book configuration file.\n\n{}\n\nFor more information try --help.",
                            matches.usage()));
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();
    let verbose = matches.is_present("verbose");
    match Book::new_from_file(s, verbose) {
        Err(err) => print_error(&format!("{}", err)),
        Ok(mut book) => {
            set_book_options(&mut book, &matches);

            if let Some(format) = matches.value_of("to") {
                render_format(&mut book, &matches, format);
            } else {
                match book.render_all() {
                    Err(err) => print_error(&format!("{}", err)),
                    Ok(_) => {
                        println!("crowbook terminated successfully");
                        exit(0);
                    }
                }
            }
        }
    }
}
<commit_msg>main.rs: fixed bug<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

extern crate crowbook;
extern crate clap;

mod helpers;
use helpers::*;

use crowbook::{Book};
use clap::ArgMatches;
use std::process::exit;
use std::fs::File;
use std::io;

/// Render a book to specific format
fn render_format(book: &mut Book, matches: &ArgMatches, format: &str) -> ! {
    if let Some(file) = matches.value_of("output") {
        match format {
            "epub" => book.set_option("output.epub", file).unwrap(),
            "tex" => book.set_option("output.tex", file).unwrap(),
            "html" => book.set_option("output.html", file).unwrap(),
            "pdf" => book.set_option("output.pdf", file).unwrap(),
            "odt" => book.set_option("output.odt", file).unwrap(),
            _ => unreachable!()
        }
    }

    let option = match format {
        "epub" => book.get_path("output.epub"),
        "tex" => book.get_path("output.tex"),
        "html" => book.get_path("output.html"),
        "pdf" => book.get_path("output.pdf"),
        "odt" => book.get_path("output.odt"),
        _ => unreachable!()
    };
    let result = match option {
        Err(_) => {
            match format {
                "html" => book.render_html(&mut io::stdout()),
                "tex" => book.render_tex(&mut io::stdout()),
                _ => print_error(&format!("No output file specified, and book doesn't specify an output file for {}", format)),
            }
        },
        Ok(file) => {
            match format {
                "epub" => book.render_epub(),
                "tex" => {
                    let mut f = File::create(file).unwrap();
                    book.render_tex(&mut f)
                },
                "html" => {
                    let mut f = File::create(file).unwrap();
                    book.render_html(&mut f)
                },
                "pdf" => book.render_pdf(),
                "odt" => book.render_odt(),
                _ => unreachable!()
            }
        }
    };
    match result {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => {
                    println!("crowbook terminated successfully");
            exit(0);
        },
    }
}

fn main() {
    let matches = create_matches();

    if matches.is_present("list-options") {
        println!("{}", Book::description(false));
        exit(0);
    }

    if matches.is_present("list-options-md") {
        println!("{}", Book::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error(&format!("{} is not a valid template name.", template)),
        }
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error(&format!("You must pass the file of a book configuration file.\n\n{}\n\nFor more information try --help.",
                            matches.usage()));
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();
    let verbose = matches.is_present("verbose");
    match Book::new_from_file(s, verbose) {
        Err(err) => print_error(&format!("{}", err)),
        Ok(mut book) => {
            set_book_options(&mut book, &matches);

            if let Some(format) = matches.value_of("to") {
                render_format(&mut book, &matches, format);
            } else {
                match book.render_all() {
                    Err(err) => print_error(&format!("{}", err)),
                    Ok(_) => {
                        println!("crowbook terminated successfully");
                        exit(0);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! [Problem 119](https://projecteuler.net/problem=119) solver.

#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(iter_arith, wrapping)]

#[macro_use(problem)]
extern crate common;
extern crate integer;

use std::cmp::Ordering;
use std::num::wrapping::OverflowingOps;
use std::collections::BinaryHeap;
use integer::Integer;

trait IntExt: Sized {
    fn checked_pow(self, exp: u32) -> Option<Self>;
}

impl IntExt for u64 {
    fn checked_pow(self, mut exp: u32) -> Option<Self> {
        let mut base = self;
        let mut acc = 1u64;

        let mut prev_base = self;
        let mut base_oflo = false;
        while exp > 0 {
            if (exp & 1) == 1 {
                let new_acc;
                if base_oflo {
                    // ensure overflow occurs in the same manner it
                    // would have otherwise (i.e. signal any exception
                    // it would have otherwise).
                    new_acc = acc.checked_mul(prev_base * prev_base);
                } else {
                    new_acc = acc.checked_mul(base);
                }
                match new_acc {
                    Some(a) => acc = a,
                    None => return None,
                }
            }
            prev_base = base;
            let (new_base, new_base_oflo) = base.overflowing_mul(base);
            base = new_base;
            base_oflo = new_base_oflo;
            exp /= 2;
        }
        Some(acc)
    }
}

struct Power(u64, u64, u32);

impl PartialEq for Power {
    fn eq(&self, other: &Power) -> bool {
        self.0 == other.0 && self.1 == other.1
    }
}

impl Eq for Power {}

impl PartialOrd for Power {
    fn partial_cmp(&self, other: &Power) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Power {
    fn cmp(&self, other: &Power) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1)).reverse()
    }
}

struct Powers {
    heap: BinaryHeap<Power>,
}

impl Powers {
    fn new() -> Powers {
        let mut heap = BinaryHeap::new();
        heap.push(Power(4, 2, 2));
        Powers { heap: heap }
    }
}

impl Iterator for Powers {
    type Item = (u64, u64, u32);

    fn next(&mut self) -> Option<(u64, u64, u32)> {
        let Power(n, b, e) = self.heap.pop().unwrap();
        if b == 2 {
            self.heap.push(Power(n * b, b, e + 1));
        }
        if b < 99 {
            // assume base is smaller than 100
            if let Some(new_n) = (b + 1).checked_pow(e) {
                self.heap.push(Power(new_n, b + 1, e));
            }
        }
        Some((n, b, e))
    }
}

fn compute_a(n: usize) -> (u64, u64, u32) {
    Powers::new()
        .skip_while(|&(n, _b, _e)| n < 10)
        .filter(|&(n, b, _e)| n.into_digits(10).sum::<u64>() == b)
        .nth(n - 1)
        .unwrap()
}

fn solve() -> String {
    let (n, _b, _e) = compute_a(30);
    n.to_string()
}

problem!("248155780267521", solve);

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

    #[test]
    fn powers() {
        let mut it = Powers::new();
        assert_eq!(Some((4, 2, 2)), it.next());
        assert_eq!(Some((8, 2, 3)), it.next());
        assert_eq!(Some((9, 3, 2)), it.next());
        assert_eq!(Some((16, 2, 4)), it.next());
        assert_eq!(Some((16, 4, 2)), it.next());
        assert_eq!(Some((25, 5, 2)), it.next());
        assert_eq!(Some((27, 3, 3)), it.next());
        assert_eq!(Some((32, 2, 5)), it.next());
        assert_eq!(Some((36, 6, 2)), it.next());
        assert_eq!(Some((49, 7, 2)), it.next());
        assert_eq!(Some((64, 2, 6)), it.next());
        assert_eq!(Some((64, 4, 3)), it.next());
        assert_eq!(Some((64, 8, 2)), it.next());
        assert_eq!(Some((81, 3, 4)), it.next());
        assert_eq!(Some((81, 9, 2)), it.next());
        assert_eq!(Some((100, 10, 2)), it.next());
    }

    #[test]
    fn compute_a() {
        assert_eq!((512, 8, 3), super::compute_a(2));
        assert_eq!((614656, 28, 4), super::compute_a(10));
    }
}
<commit_msg>update to rustc 1.7.0-nightly (d0bac3f14 2016-01-18)<commit_after>//! [Problem 119](https://projecteuler.net/problem=119) solver.

#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(iter_arith)]

#[macro_use(problem)]
extern crate common;
extern crate integer;

use std::cmp::Ordering;
use std::collections::BinaryHeap;
use integer::Integer;

trait IntExt: Sized {
    fn checked_pow(self, exp: u32) -> Option<Self>;
}

impl IntExt for u64 {
    fn checked_pow(self, mut exp: u32) -> Option<Self> {
        let mut base = self;
        let mut acc = 1u64;

        let mut prev_base = self;
        let mut base_oflo = false;
        while exp > 0 {
            if (exp & 1) == 1 {
                let new_acc;
                if base_oflo {
                    // ensure overflow occurs in the same manner it
                    // would have otherwise (i.e. signal any exception
                    // it would have otherwise).
                    new_acc = acc.checked_mul(prev_base * prev_base);
                } else {
                    new_acc = acc.checked_mul(base);
                }
                match new_acc {
                    Some(a) => acc = a,
                    None => return None,
                }
            }
            prev_base = base;
            let (new_base, new_base_oflo) = base.overflowing_mul(base);
            base = new_base;
            base_oflo = new_base_oflo;
            exp /= 2;
        }
        Some(acc)
    }
}

struct Power(u64, u64, u32);

impl PartialEq for Power {
    fn eq(&self, other: &Power) -> bool {
        self.0 == other.0 && self.1 == other.1
    }
}

impl Eq for Power {}

impl PartialOrd for Power {
    fn partial_cmp(&self, other: &Power) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Power {
    fn cmp(&self, other: &Power) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1)).reverse()
    }
}

struct Powers {
    heap: BinaryHeap<Power>,
}

impl Powers {
    fn new() -> Powers {
        let mut heap = BinaryHeap::new();
        heap.push(Power(4, 2, 2));
        Powers { heap: heap }
    }
}

impl Iterator for Powers {
    type Item = (u64, u64, u32);

    fn next(&mut self) -> Option<(u64, u64, u32)> {
        let Power(n, b, e) = self.heap.pop().unwrap();
        if b == 2 {
            self.heap.push(Power(n * b, b, e + 1));
        }
        if b < 99 {
            // assume base is smaller than 100
            if let Some(new_n) = (b + 1).checked_pow(e) {
                self.heap.push(Power(new_n, b + 1, e));
            }
        }
        Some((n, b, e))
    }
}

fn compute_a(n: usize) -> (u64, u64, u32) {
    Powers::new()
        .skip_while(|&(n, _b, _e)| n < 10)
        .filter(|&(n, b, _e)| n.into_digits(10).sum::<u64>() == b)
        .nth(n - 1)
        .unwrap()
}

fn solve() -> String {
    let (n, _b, _e) = compute_a(30);
    n.to_string()
}

problem!("248155780267521", solve);

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

    #[test]
    fn powers() {
        let mut it = Powers::new();
        assert_eq!(Some((4, 2, 2)), it.next());
        assert_eq!(Some((8, 2, 3)), it.next());
        assert_eq!(Some((9, 3, 2)), it.next());
        assert_eq!(Some((16, 2, 4)), it.next());
        assert_eq!(Some((16, 4, 2)), it.next());
        assert_eq!(Some((25, 5, 2)), it.next());
        assert_eq!(Some((27, 3, 3)), it.next());
        assert_eq!(Some((32, 2, 5)), it.next());
        assert_eq!(Some((36, 6, 2)), it.next());
        assert_eq!(Some((49, 7, 2)), it.next());
        assert_eq!(Some((64, 2, 6)), it.next());
        assert_eq!(Some((64, 4, 3)), it.next());
        assert_eq!(Some((64, 8, 2)), it.next());
        assert_eq!(Some((81, 3, 4)), it.next());
        assert_eq!(Some((81, 9, 2)), it.next());
        assert_eq!(Some((100, 10, 2)), it.next());
    }

    #[test]
    fn compute_a() {
        assert_eq!((512, 8, 3), super::compute_a(2));
        assert_eq!((614656, 28, 4), super::compute_a(10));
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::str;
use std::fs::File;
use std::process::exit;
use std::io::{stdout, stderr, stdin, Error, Write, BufRead, BufReader, BufWriter};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = r#"
NAME
    uniq - report or omit repeated lines

SYNOPSIS
    uniq [ -h | --help | -d | -u | -i ] [FILE]...

DESCRIPTION
    Filter adjacent matching lines of FILE(s) to standard output.

    With no FILE(s), read standard input.

OPTIONS
    -h
    --help
        display this help and exit
    -c
    --count
        precede each output line with a count of the number of times the line occurred in the input
    -i
    --ignore-case
        compare lines case-insensitively
    -d
    --repeated-lines
        only print duplicate lines, one for each group
    -u
    --unique-lines
        only print unique lines
"#; /* @MANEND */

fn lines_from_stdin() -> Result<Vec<Vec<u8>>, Error> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let f = BufReader::new(stdin.lock());
    for line in f.split(b'\n') {
        lines.push(line?);
    }
    Ok(lines)
}

fn lines_from_files(paths: &Vec<&String>) -> Result<Vec<Vec<u8>>, Error> {
    let mut lines = Vec::new();

    for path in paths {
        let f = BufReader::new(File::open(path)?);
        for line in f.split(b'\n') {
            lines.push(line?);
        }
    }
    Ok(lines)
}

fn eq_strings(left: &Vec<u8>, right: &Vec<u8>, ignore_case: bool) -> bool {
    if ignore_case {
        left.len() == right.len() &&
        left
            .iter()
            .zip(right.iter())
            .all(|(&l, &r)|  l | 0x20 == r | 0x20)

    } else {
        left == right
    }
}

fn get_squashed_lines(lines: &Vec<Vec<u8>>, ignore_case: bool) -> Vec<(usize, &Vec<u8>)> {
    let mut squashed =  Vec::new();
    let llen = lines.len();

    let mut r: usize = 0;

    while r < llen {
        let mut rnext: usize = r + 1;
        let mut count: usize = 1;

        while rnext < llen && eq_strings(&lines[r], &lines[rnext], ignore_case) {
            count += 1;
            rnext += 1;
        }

        squashed.push((count, &lines[r]));
        r += count;
    }

    squashed
}

fn unique_lines(lines: Vec<(usize, &Vec<u8>)>) -> Vec<(usize, &Vec<u8>)> {
   lines.into_iter()
       .filter(|&(k,_)| k == 1)
       .collect::<Vec<_>>()
}

fn repeated_lines(lines: Vec<(usize, &Vec<u8>)>) -> Vec<(usize, &Vec<u8>)> {
   lines.into_iter()
       .filter(|&(k,_)| k > 1)
       .collect::<Vec<_>>()
}

fn main() {

    let stdout = stdout();
    let mut stdout = BufWriter::with_capacity(8192, stdout.lock());
    let mut stderr = stderr();
    let mut parser = ArgParser::new(5)
        .add_flag(&["i", "ignore-case"])
        .add_flag(&["c", "count"])
        .add_flag(&["d", "repeated-lines"])
        .add_flag(&["u", "unique-lines"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let lines = match parser.args.is_empty() {
        true => lines_from_stdin(),
        false => {
            let paths = parser.args.iter().collect::<Vec<_>>();
            lines_from_files(&paths)
        }
    };

    match lines {
        Ok(ref l) => {
            let mut squashed = get_squashed_lines(&l, parser.found("ignore-case"));

            if parser.found("unique-lines") {
                squashed = unique_lines(squashed);
            } else if parser.found("repeated-lines") {
                squashed = repeated_lines(squashed);
            }

            if parser.found("count") {
                for (c, v) in squashed {
                    let _ = stdout.write_fmt(format_args!("{} ", c))
                        .and_then(|_| stdout.write_all(b" "))
                        .and_then(|_| stdout.write_all(v))
                        .and_then(|_| stdout.write_all(b"\n"));
                }
            } else {
                for (_, v) in squashed {
                    let _ = stdout.write_all(v)
                        .and_then(|_| stdout.write_all(b"\n"));
                }
            }
        }
        Err(e) => {
            let _ = write!(stderr, "{}", e);
        }
    }
}
<commit_msg>Add --skip-lines option to uniq<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::str;
use std::fs::File;
use std::process::exit;
use std::io::{stdout, stderr, stdin, Error, Write, BufRead, BufReader, BufWriter};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const HELP_INFO:       &'static str = "Try ‘uniq --help’ for more information.\n";
const REQUIRES_OPTION: &'static str = "option requires an argument\n";
const MAN_PAGE: &'static str = r#"
NAME
    uniq - report or omit repeated lines

SYNOPSIS
    uniq [ -h | --help | -d | -u | -i ] [FILE]...

DESCRIPTION
    Filter adjacent matching lines of FILE(s) to standard output.

    With no FILE(s), read standard input.

OPTIONS
    -c
    --count
        precede each output line with a count of the number of times the line occurred in the input
    -d
    --repeated-lines
        only print duplicate lines, one for each group
    -i
    --ignore-case
        compare lines case-insensitively
    -s
    --skip-chars=N
        avoid comparing the first N characters
    -u
    --unique-lines
        only print unique lines
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn lines_from_stdin() -> Result<Vec<Vec<u8>>, Error> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let f = BufReader::new(stdin.lock());
    for line in f.split(b'\n') {
        lines.push(line?);
    }
    Ok(lines)
}

fn lines_from_files(paths: &Vec<&String>) -> Result<Vec<Vec<u8>>, Error> {
    let mut lines = Vec::new();

    for path in paths {
        let f = BufReader::new(File::open(path)?);
        for line in f.split(b'\n') {
            lines.push(line?);
        }
    }
    Ok(lines)
}

fn eq_strings(left: &Vec<u8>, right: &Vec<u8>, skip_chars: usize, ignore_case: bool) -> bool {
    let left = if skip_chars >= left.len() { &[] } else { &left[skip_chars..] };
    let right = if skip_chars >= right.len() { &[] } else { &right[skip_chars..] };

    if ignore_case {
        left.len() == right.len() &&
        left
            .iter()
            .zip(right.iter())
            .all(|(&l, &r)|  l | 0x20 == r | 0x20)

    } else {
        left == right
    }
}

fn get_squashed_lines(lines: &Vec<Vec<u8>>, skip_chars: usize, ignore_case: bool) -> Vec<(usize, &Vec<u8>)> {
    let mut squashed =  Vec::new();
    let llen = lines.len();

    let mut r: usize = 0;

    while r < llen {
        let mut rnext: usize = r + 1;
        let mut count: usize = 1;

        while rnext < llen && eq_strings(&lines[r], &lines[rnext], skip_chars, ignore_case) {
            count += 1;
            rnext += 1;
        }

        squashed.push((count, &lines[r]));
        r += count;
    }

    squashed
}

fn unique_lines(lines: Vec<(usize, &Vec<u8>)>) -> Vec<(usize, &Vec<u8>)> {
   lines.into_iter()
       .filter(|&(k,_)| k == 1)
       .collect::<Vec<_>>()
}

fn repeated_lines(lines: Vec<(usize, &Vec<u8>)>) -> Vec<(usize, &Vec<u8>)> {
   lines.into_iter()
       .filter(|&(k,_)| k > 1)
       .collect::<Vec<_>>()
}

fn main() {

    let stdout = stdout();
    let mut stdout = BufWriter::with_capacity(8192, stdout.lock());
    let mut stderr = stderr();
    let mut parser = ArgParser::new(6)
        .add_opt("s", "skip-chars")
        .add_flag(&["c", "count"])
        .add_flag(&["d", "repeated-lines"])
        .add_flag(&["i", "ignore-case"])
        .add_flag(&["u", "unique-lines"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let lines = match parser.args.is_empty() {
        true => lines_from_stdin(),
        false => {
            let paths = parser.args.iter().collect::<Vec<_>>();
            lines_from_files(&paths)
        }
    };

    match lines {
        Ok(ref l) => {
            let mut skip_chars: usize = 0;
            if parser.found(&'s') || parser.found("skip-chars") {
                if let Some(c) = parser.get_opt(&'s') {
                    skip_chars = c.parse::<usize>().try(&mut stderr);
                } else if let Some(c) = parser.get_opt("skip-chars") {
                    skip_chars = c.parse::<usize>().try(&mut stderr);
                } else {
                    stderr.write_all(REQUIRES_OPTION.as_bytes()).try(&mut stderr);
                    stdout.write_all(HELP_INFO.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                }
            }

            let mut squashed = get_squashed_lines(&l, skip_chars, parser.found("ignore-case"));

            if parser.found("unique-lines") {
                squashed = unique_lines(squashed);
            } else if parser.found("repeated-lines") {
                squashed = repeated_lines(squashed);
            }

            if parser.found("count") {
                for (c, v) in squashed {
                    let _ = stdout.write_fmt(format_args!("{} ", c))
                        .and_then(|_| stdout.write_all(b" "))
                        .and_then(|_| stdout.write_all(v))
                        .and_then(|_| stdout.write_all(b"\n"));
                }
            } else {
                for (_, v) in squashed {
                    let _ = stdout.write_all(v)
                        .and_then(|_| stdout.write_all(b"\n"));
                }
            }
        }
        Err(e) => {
            let _ = write!(stderr, "{}", e);
        }
    }
}
<|endoftext|>


<commit_before>use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;

declare_lint! {
    pub BAD_BIT_MASK,
    Deny,
    "Deny the use of incompatible bit masks in comparisons, e.g. \
    '(a & 1) == 2'"
}

declare_lint! {
	pub INEFFECTIVE_BIT_MASK,
	Warn,
	"Warn on the use of an ineffective bit mask in comparisons, e.g. \
	'(a & 1) > 2'"
}

/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
/// This cannot work because the bit that makes up the value two was
/// zeroed out by the bit-and with 1. So the formula for detecting if an
/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `!=`, `>=`, `>`}) can be determined from the following table:
///
/// |Comparison  |Bit-Op|Example     |is always|Formula               |
/// |------------|------|------------|---------|----------------------|
/// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
/// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
/// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
/// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
/// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`			  |
/// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
///
/// This lint is **deny** by default
///
/// There is also a lint that warns on ineffective masks that is *warn*
/// by default
#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
			if is_comparison_binop(cmp.node) {
				fetch_int_literal(cx, right).map_or_else(||
					fetch_int_literal(cx, left).map_or((), |cmp_val|
						check_compare(cx, right, invert_cmp(cmp.node),
							cmp_val, &e.span)),
					|cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
						&e.span))
			}
		}
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
	match cmp {
		BiEq => BiEq,
		BiNe => BiNe,
		BiLt => BiGt,
		BiGt => BiLt,
		BiLe => BiGe,
		BiGe => BiLe,
		_ => BiOr // Dummy
	}
}

fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
	match &bit_op.node {
		&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
		&ExprBinary(ref op, ref left, ref right) => {
			if op.node != BiBitAnd && op.node != BiBitOr { return; }
			fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
				cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
					cmp_op, mask, cmp_value, span))
		},
		_ => ()
	}
}

fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) {
	match cmp_op {
		BiEq | BiNe => match bit_op {
			BiBitAnd => if mask_value & cmp_value != mask_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value | cmp_value != cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLt | BiGe => match bit_op {
			BiBitAnd => if mask_value < cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ & {} will always be lower than {}",
					mask_value, cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value >= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ | {} will never be lower than {}",
					mask_value, cmp_value));
			} else {
				if mask_value < cmp_value {
					cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
						"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
						mask_value, cmp_value));
				}
			},
			_ => ()
		},
		BiLe | BiGt => match bit_op {
			BiBitAnd => if mask_value <= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ & {} will never be higher than {}",
					mask_value, cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value > cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ | {} will always be higher than {}",
					mask_value, cmp_value));
			} else {
				if mask_value < cmp_value {
					cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
						"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
						mask_value, cmp_value));
				}
			},
			_ => ()
		},
		_ => ()
	}
}

fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
	match &lit.node {
		&ExprLit(ref lit_ptr) => {
			if let &LitInt(value, _) = &lit_ptr.node {
				Option::Some(value) //TODO: Handle sign
			} else { Option::None }
		},
		&ExprPath(_, _) => {
                // Important to let the borrow expire before the const lookup to avoid double
                // borrowing.
                let def_map = cx.tcx.def_map.borrow();
                match def_map.get(&lit.id) {
                    Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
                    _ => None
                }
            }
            .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
            .and_then(|l| fetch_int_literal(cx, l)),
		_ => Option::None
	}
}
<commit_msg>Formatting fixed<commit_after>use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;

declare_lint! {
    pub BAD_BIT_MASK,
    Deny,
    "Deny the use of incompatible bit masks in comparisons, e.g. \
    '(a & 1) == 2'"
}

declare_lint! {
	pub INEFFECTIVE_BIT_MASK,
	Warn,
	"Warn on the use of an ineffective bit mask in comparisons, e.g. \
	'(a & 1) > 2'"
}

/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
/// This cannot work because the bit that makes up the value two was
/// zeroed out by the bit-and with 1. So the formula for detecting if an
/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `!=`, `>=`, `>`}) can be determined from the following table:
///
/// |Comparison  |Bit-Op|Example     |is always|Formula               |
/// |------------|------|------------|---------|----------------------|
/// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
/// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
/// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
/// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
/// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
/// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
///
/// This lint is **deny** by default
///
/// There is also a lint that warns on ineffective masks that is *warn*
/// by default
#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
			if is_comparison_binop(cmp.node) {
				fetch_int_literal(cx, right).map_or_else(||
					fetch_int_literal(cx, left).map_or((), |cmp_val|
						check_compare(cx, right, invert_cmp(cmp.node),
							cmp_val, &e.span)),
					|cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
						&e.span))
			}
		}
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
	match cmp {
		BiEq => BiEq,
		BiNe => BiNe,
		BiLt => BiGt,
		BiGt => BiLt,
		BiLe => BiGe,
		BiGe => BiLe,
		_ => BiOr // Dummy
	}
}

fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
	match &bit_op.node {
		&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
		&ExprBinary(ref op, ref left, ref right) => {
			if op.node != BiBitAnd && op.node != BiBitOr { return; }
			fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
				cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
					cmp_op, mask, cmp_value, span))
		},
		_ => ()
	}
}

fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) {
	match cmp_op {
		BiEq | BiNe => match bit_op {
			BiBitAnd => if mask_value & cmp_value != mask_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value | cmp_value != cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLt | BiGe => match bit_op {
			BiBitAnd => if mask_value < cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ & {} will always be lower than {}",
					mask_value, cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value >= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ | {} will never be lower than {}",
					mask_value, cmp_value));
			} else {
				if mask_value < cmp_value {
					cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
						"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
						mask_value, cmp_value));
				}
			},
			_ => ()
		},
		BiLe | BiGt => match bit_op {
			BiBitAnd => if mask_value <= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ & {} will never be higher than {}",
					mask_value, cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value > cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!(
					"incompatible bit mask: _ | {} will always be higher than {}",
					mask_value, cmp_value));
			} else {
				if mask_value < cmp_value {
					cx.span_lint(INEFFECTIVE_BIT_MASK, *span, &format!(
						"ineffective bit mask: x | {} compared to {} is the same as x compared directly",
						mask_value, cmp_value));
				}
			},
			_ => ()
		},
		_ => ()
	}
}

fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
	match &lit.node {
		&ExprLit(ref lit_ptr) => {
			if let &LitInt(value, _) = &lit_ptr.node {
				Option::Some(value) //TODO: Handle sign
			} else { Option::None }
		},
		&ExprPath(_, _) => {
                // Important to let the borrow expire before the const lookup to avoid double
                // borrowing.
                let def_map = cx.tcx.def_map.borrow();
                match def_map.get(&lit.id) {
                    Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
                    _ => None
                }
            }
            .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
            .and_then(|l| fetch_int_literal(cx, l)),
		_ => Option::None
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2016 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */

//! DNS Client associated classes for performing queries and other operations.

mod client;
mod client_connection;
mod client_future;
mod memoize_client_handle;
mod rc_future;

#[cfg(any(feature = "openssl", feature = "ring"))]
pub use self::client::SecureSyncClient;
#[allow(deprecated)]
pub use self::client::{Client, SyncClient};
pub use self::client_connection::ClientConnection;
#[allow(deprecated)]
pub use self::client_future::{BasicClientHandle, ClientFuture, ClientHandle};
pub use self::memoize_client_handle::MemoizeClientHandle;

/// This is an alias for [`trust_dns_proto::StreamHandle`]
#[deprecated(note = "use [`trust_dns_proto::StreamHandle`] instead")]
pub use proto::StreamHandle;

/// This is an alias for [`trust_dns_proto::DnsStreamHandle`]
#[deprecated(note = "use [`trust_dns_proto::DnsStreamHandle`] instead")]
pub use proto::DnsStreamHandle as ClientStreamHandle;

/// This is an alias for [`trust_dns_proto::RetryDnsHandle`]
#[deprecated(note = "use [`trust_dns_proto::RetryDnsHandle`] instead")]
pub use proto::RetryDnsHandle as RetryClientHandle;

/// This is an alias for [`trust_dns_proto::SecureDnsHandle`]
#[cfg(feature = "dnssec")]
#[deprecated(note = "use [`trust_dns_proto::SecureDnsHandle`] instead")]
pub use proto::SecureDnsHandle as SecureClientHandle;
<commit_msg>make ClientResponse public in client module (#617)<commit_after>/*
 * Copyright (C) 2015-2016 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */

//! DNS Client associated classes for performing queries and other operations.

mod client;
mod client_connection;
mod client_future;
mod memoize_client_handle;
mod rc_future;

#[cfg(any(feature = "openssl", feature = "ring"))]
pub use self::client::SecureSyncClient;
#[allow(deprecated)]
pub use self::client::{Client, SyncClient};
pub use self::client_connection::ClientConnection;
#[allow(deprecated)]
pub use self::client_future::{BasicClientHandle, ClientFuture, ClientHandle, ClientResponse};
pub use self::memoize_client_handle::MemoizeClientHandle;

/// This is an alias for [`trust_dns_proto::StreamHandle`]
#[deprecated(note = "use [`trust_dns_proto::StreamHandle`] instead")]
pub use proto::StreamHandle;

/// This is an alias for [`trust_dns_proto::DnsStreamHandle`]
#[deprecated(note = "use [`trust_dns_proto::DnsStreamHandle`] instead")]
pub use proto::DnsStreamHandle as ClientStreamHandle;

/// This is an alias for [`trust_dns_proto::RetryDnsHandle`]
#[deprecated(note = "use [`trust_dns_proto::RetryDnsHandle`] instead")]
pub use proto::RetryDnsHandle as RetryClientHandle;

/// This is an alias for [`trust_dns_proto::SecureDnsHandle`]
#[cfg(feature = "dnssec")]
#[deprecated(note = "use [`trust_dns_proto::SecureDnsHandle`] instead")]
pub use proto::SecureDnsHandle as SecureClientHandle;
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    sync::Arc,
};

use crate::prelude::*;

use super::behaviors::{MouseBehavior, SelectionBehavior};

static CONTAINER: &'static str = "container";
static ITEMS_PANEL: &'static str = "items_panel";

type SelectedItem = Option<Entity>;

#[derive(Debug, Copy, Clone)]
enum Action {
    CheckMouseUpOutside { x: f64, y: f64 },
}

/// The `ComboBoxItemState` handles the interaction an selection of a `ComboBoxItem`.
#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    index: usize,
    selected_container: Entity,
    combo_box: Entity,
    // ugly work around for item builder context clone, todo make it better 😉
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let selected_index = ctx
            .get_widget(self.combo_box)
            .clone_or_default::<i32>("selected_index");
        let selected: bool = *ctx.widget().get("selected");

        if selected_index >= 0 && (selected_index as usize) == self.index && !selected {
            self.request_selection_toggle.set(true);
        }

        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let entity = ctx.entity;

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item).update_theme_by_state(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget().update_theme_by_state(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", self.index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));

        // Add selected content to combobox
        let index = self.index;
        let selected_container = self.selected_container;
        if let Some(builder) = &self.builder {
            ctx.clear_children_of(selected_container);
            let build_context = &mut ctx.build_context();
            let selected_content = builder.borrow()(build_context, index);
            build_context.append_child(selected_container, selected_content);
        }
    }
}

widget!(
    /// The `ComboBoxItem` describes an item inside of a `ComboBox`.
    ///
    /// **CSS element:** `combo_box_item``
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn index(mut self, index: usize) -> Self {
        self.state_mut().index = index;
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder(
        &mut self,
        builder: &Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>,
    ) {
        self.state_mut().builder = Some(builder.clone());
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .element("combo_box_item")
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    popup: Entity,
    action: Option<Action>,
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl ComboBoxState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }

    // closes the popup on mouse up outside of the combobox and popup.
    fn close_popup(&mut self, ctx: &mut Context, x: f64, y: f64) {
        let combo_box_position = ctx.widget().clone::<Point>("position");
        let combo_box_bounds = ctx.widget().clone::<Rectangle>("bounds");

        let combo_box_global_bounds = Rectangle::new(
            combo_box_position.x,
            combo_box_position.y,
            combo_box_bounds.width,
            combo_box_bounds.height,
        );

        let popup_position = ctx.get_widget(self.popup).clone::<Point>("position");
        let popup_bounds = ctx.get_widget(self.popup).clone::<Rectangle>("bounds");

        let popup_global_bounds = Rectangle::new(
            popup_position.x,
            popup_position.y,
            popup_bounds.width,
            popup_bounds.height,
        );

        if !combo_box_global_bounds.contains((x, y)) {
            ctx.widget().set("selected", false);
            ctx.get_widget(self.popup)
                .set("visibility", Visibility::Collapsed);
            ctx.get_widget(self.popup).update_theme_by_state(false);
            ctx.widget().update_theme_by_state(false);
        }
    }
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        // build the combobox items
        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder.borrow()(build_context, i);
                        let mut item = ComboBoxItem::create()
                            .index(i)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        if let Some(builder) = &self.builder {
                            item.items_builder(builder);
                        }
                        let item = item.build(build_context);

                        let mouse_behavior = MouseBehavior::create().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_properties_by_theme();
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        if self.action.is_none() || !(*ctx.widget().get::<bool>("selected")) {
            return;
        }

        if let Some(action) = self.action {
            match action {
                Action::CheckMouseUpOutside { x, y } => {
                    self.close_popup(ctx, x, y);
                }
            }
        }
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **CSS element:** `combo_box`
    ComboBox<ComboBoxState>: MouseHandler, ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Arc::new(RefCell::new(builder)));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let selected_container = Container::create().attach(Grid::column(0)).build(ctx);

        let container = Container::create()
            .id(CONTAINER)
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .child(
                Grid::create()
                    .columns(
                        Columns::create()
                            .column("*")
                            .column(4.0)
                            .column(14.0)
                            .build(),
                    )
                    .child(selected_container)
                    .child(
                        FontIconBlock::create()
                            .attach(Grid::column(2))
                            .vertical_alignment("center")
                            .icon(material_font_icons::ARROW_DOWN_ICON)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .build(ctx);
        self.state_mut().selected_container = selected_container;

        let items_panel = Stack::create()
            .vertical_alignment("start")
            .id(ITEMS_PANEL)
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::create()
            .scroll_viewer_mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::create()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::create()
                    .padding(2.0)
                    .content_id(items_panel.0)
                    .scroll_offset(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);
        self.state_mut().popup = popup;

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .element("combo_box")
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::create()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::create()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_global_mouse_up(move |states, e| {
                states
                    .get_mut::<ComboBoxState>(id)
                    .action(Action::CheckMouseUpOutside { x: e.x, y: e.y })
            })
    }
}
<commit_msg>ComboBox: Removed dead code<commit_after>use std::{
    cell::{Cell, RefCell},
    sync::Arc,
};

use crate::prelude::*;

use super::behaviors::{MouseBehavior, SelectionBehavior};

static CONTAINER: &'static str = "container";
static ITEMS_PANEL: &'static str = "items_panel";

type SelectedItem = Option<Entity>;

#[derive(Debug, Copy, Clone)]
enum Action {
    CheckMouseUpOutside { x: f64, y: f64 },
}

/// The `ComboBoxItemState` handles the interaction an selection of a `ComboBoxItem`.
#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    index: usize,
    selected_container: Entity,
    combo_box: Entity,
    // ugly work around for item builder context clone, todo make it better 😉
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let selected_index = ctx
            .get_widget(self.combo_box)
            .clone_or_default::<i32>("selected_index");
        let selected: bool = *ctx.widget().get("selected");

        if selected_index >= 0 && (selected_index as usize) == self.index && !selected {
            self.request_selection_toggle.set(true);
        }

        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let entity = ctx.entity;

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item).update_theme_by_state(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget().update_theme_by_state(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", self.index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));

        // Add selected content to combobox
        let index = self.index;
        let selected_container = self.selected_container;
        if let Some(builder) = &self.builder {
            ctx.clear_children_of(selected_container);
            let build_context = &mut ctx.build_context();
            let selected_content = builder.borrow()(build_context, index);
            build_context.append_child(selected_container, selected_content);
        }
    }
}

widget!(
    /// The `ComboBoxItem` describes an item inside of a `ComboBox`.
    ///
    /// **CSS element:** `combo_box_item``
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn index(mut self, index: usize) -> Self {
        self.state_mut().index = index;
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder(
        &mut self,
        builder: &Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>,
    ) {
        self.state_mut().builder = Some(builder.clone());
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .element("combo_box_item")
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    popup: Entity,
    action: Option<Action>,
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl ComboBoxState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }

    // closes the popup on mouse up outside of the combobox and popup.
    fn close_popup(&mut self, ctx: &mut Context, x: f64, y: f64) {
        let combo_box_position = ctx.widget().clone::<Point>("position");
        let combo_box_bounds = ctx.widget().clone::<Rectangle>("bounds");

        let combo_box_global_bounds = Rectangle::new(
            combo_box_position.x,
            combo_box_position.y,
            combo_box_bounds.width,
            combo_box_bounds.height,
        );

        if !combo_box_global_bounds.contains((x, y)) {
            ctx.widget().set("selected", false);
            ctx.get_widget(self.popup)
                .set("visibility", Visibility::Collapsed);
            ctx.get_widget(self.popup).update_theme_by_state(false);
            ctx.widget().update_theme_by_state(false);
        }
    }
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        // build the combobox items
        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder.borrow()(build_context, i);
                        let mut item = ComboBoxItem::create()
                            .index(i)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        if let Some(builder) = &self.builder {
                            item.items_builder(builder);
                        }
                        let item = item.build(build_context);

                        let mouse_behavior = MouseBehavior::create().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_properties_by_theme();
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        if self.action.is_none() || !(*ctx.widget().get::<bool>("selected")) {
            return;
        }

        if let Some(action) = self.action {
            match action {
                Action::CheckMouseUpOutside { x, y } => {
                    self.close_popup(ctx, x, y);
                }
            }
        }
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **CSS element:** `combo_box`
    ComboBox<ComboBoxState>: MouseHandler, ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Arc::new(RefCell::new(builder)));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let selected_container = Container::create().attach(Grid::column(0)).build(ctx);

        let container = Container::create()
            .id(CONTAINER)
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .child(
                Grid::create()
                    .columns(
                        Columns::create()
                            .column("*")
                            .column(4.0)
                            .column(14.0)
                            .build(),
                    )
                    .child(selected_container)
                    .child(
                        FontIconBlock::create()
                            .attach(Grid::column(2))
                            .vertical_alignment("center")
                            .icon(material_font_icons::ARROW_DOWN_ICON)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .build(ctx);
        self.state_mut().selected_container = selected_container;

        let items_panel = Stack::create()
            .vertical_alignment("start")
            .id(ITEMS_PANEL)
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::create()
            .scroll_viewer_mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::create()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::create()
                    .padding(2.0)
                    .content_id(items_panel.0)
                    .scroll_offset(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);
        self.state_mut().popup = popup;

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .element("combo_box")
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::create()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::create()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_global_mouse_up(move |states, e| {
                states
                    .get_mut::<ComboBoxState>(id)
                    .action(Action::CheckMouseUpOutside { x: e.x, y: e.y })
            })
    }
}
<|endoftext|>