<commit_before>//! A Little implementation of the roulette-wheel principle, `RouletteWheel<T>`.
//! https://wikipedia.org/wiki/Fitness_proportionate_selection
//!
//! ![Fitness proportionate selection](https://upload.wikimedia.org/wikipedia/commons/2/2a/Fitness_proportionate_selection_example.png)
//!
//! # Usage
//!
//! # Examples
//!
//! You can explicitly create a `RouletteWheel<T>` with `new()`:
//!
//! ```
//! use roulette_wheel::RouletteWheel;
//!
//! let rw: RouletteWheel<u8> = RouletteWheel::new();
//! ```
//!
//! You can `push` values in the roulette-wheel (which will grow the wheel as needed):
//! ```
//! use roulette_wheel::RouletteWheel;
//!
//! let mut rw = RouletteWheel::new();
//!
//! rw.push(5., 'a');
//! rw.push(1., 'b');
//!
//! // .iter() will not consume the roulette wheel
//! for (fit, &ind) in rw.iter() {
//!    // do things with individuals here
//! }
//!
//! // .into_iter() consume the roulette wheel
//! for (fit, ind) in rw.into_iter() {
//!     // do things with individuals here
//! }
//!
//! ```

extern crate rand;

use std::iter::{FromIterator, Iterator, IntoIterator};
use rand::{Rng, ThreadRng, thread_rng};
use rand::distributions::{Range, IndependentSample};

/// A roulette-wheel container
pub struct RouletteWheel<T> {
    total_fitness: f32,
    fitnesses: Vec<f32>,
    population: Vec<T>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: self.total_fitness,
            fitnesses: self.fitnesses.clone(),
            population: self.population.clone()
        }
    }
}

impl<T> FromIterator<(f32, T)> for RouletteWheel<T> {
    fn from_iter<A>(iter: A) -> Self where A: IntoIterator<Item=(f32, T)> {
        let iter = iter.into_iter();
        let (lower, _) = iter.size_hint();

        let mut total_fitness = 0.0;
        let mut fitnesses = Vec::with_capacity(lower);
        let mut population = Vec::with_capacity(lower);

        for (fitness, individual) in iter {
            total_fitness += fitness;
            fitnesses.push(fitness);
            population.push(individual);
        }

        RouletteWheel {
            total_fitness: total_fitness,
            fitnesses: fitnesses,
            population: population
        }

        // #![feature(field_init_shorthand)]
        // RouletteWheel { total_fitness, fitnesses, population }
    }
}

impl<T> RouletteWheel<T> {
    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw = RouletteWheel::<u8>::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::new(),
            population: Vec::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw = RouletteWheel::<u8>::with_capacity(15);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(cap: usize) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::with_capacity(cap),
            population: Vec::with_capacity(cap)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::<u8>::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.fitnesses.reserve(additional);
        self.population.reserve(additional);
    }

    /// Returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.population.len()
    }

    /// Returns `true` if empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let empty_rw = RouletteWheel::<u8>::new();
    ///
    /// assert_eq!(empty_rw.is_empty(), true);
    ///
    /// let non_empty_rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(non_empty_rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.population.is_empty()
    }

    /// Remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.fitnesses.clear();
        self.population.clear();
    }

    /// Add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, fitness: f32, individual: T) {
        assert!(fitness >= 0.0, "Can't push the less than zero fitness: {:?}", fitness);
        assert!((self.total_fitness + fitness).is_finite(), "Fitnesses sum reached a non-finite value!");
        unsafe { self.unchecked_push(fitness, individual) }
    }

    /// Add an element associated with a probability.
    /// This unsafe function doesn't check for total fitness overflow
    /// nether fitness positivity.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// unsafe { rw.unchecked_push(1.0, 'r') };
    /// unsafe { rw.unchecked_push(1.0, 'c') };
    /// unsafe { rw.unchecked_push(1.0, 'a') };
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub unsafe fn unchecked_push(&mut self, fitness: f32, individual: T) {
        self.total_fitness += fitness;
        self.fitnesses.push(fitness);
        self.population.push(individual);
    }

    /// Returns the sum of all individual fitnesses.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(3.0, 'r');
    /// rw.push(2.0, 'c');
    /// rw.push(1.5, 'a');
    ///
    /// assert_eq!(rw.total_fitness(), 6.5);
    /// ```
    pub fn total_fitness(&self) -> f32 {
        self.total_fitness
    }

    pub fn select_iter(&self) -> SelectIter<ThreadRng, T> {
        SelectIter::<ThreadRng, _>::new(&self)
    }
}

pub struct SelectIter<'a, R: Rng, T: 'a> {
    distribution_range: Range<f32>,
    rng: R,
    total_fitness: f32,
    fitnesses_ids: Vec<(usize, f32)>,
    roulette_wheel: &'a RouletteWheel<T>
}

impl<'a, R: Rng, T> SelectIter<'a, R, T> {
    pub fn new(roulette_wheel: &'a RouletteWheel<T>) -> SelectIter<'a, ThreadRng, T> {
        SelectIter::from_rng(roulette_wheel, thread_rng())
    }

    pub fn from_rng(roulette_wheel: &'a RouletteWheel<T>, rng: R) -> SelectIter<'a, R, T> {
        SelectIter {
            distribution_range: Range::new(0.0, 1.0),
            rng: rng,
            total_fitness: roulette_wheel.total_fitness,
            fitnesses_ids: roulette_wheel.fitnesses.iter().cloned().enumerate().collect(),
            roulette_wheel: roulette_wheel
        }
    }
}

impl<'a, R: Rng, T: 'a> Iterator for SelectIter<'a, R, T> {
    type Item = (f32, &'a T);

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.fitnesses_ids.len(), Some(self.fitnesses_ids.len()))
    }

    fn next(&mut self) -> Option<Self::Item> {
        if !self.fitnesses_ids.is_empty() {
            let sample = self.distribution_range.ind_sample(&mut self.rng);
            let mut selection = sample * self.total_fitness;
            let index = self.fitnesses_ids.iter().position(|&(_, fit)| {
                            selection -= fit;
                            selection <= 0.0
                        }).unwrap();
            let (index, fitness) = self.fitnesses_ids.swap_remove(index);
            self.total_fitness -= fitness;
            Some((fitness, &self.roulette_wheel.population[index]))
        }
        else { None }
    }
}

impl<T> IntoIterator for RouletteWheel<T> {
    type Item = (f32, T);
    type IntoIter = IntoSelectIter<ThreadRng, T>;

    fn into_iter(self) -> IntoSelectIter<ThreadRng, T> {
        IntoSelectIter::<ThreadRng, _>::new(self)
    }
}

pub struct IntoSelectIter<R: Rng, T> {
    distribution_range: Range<f32>,
    rng: R,
    total_fitness: f32,
    fitnesses: Vec<f32>,
    population: Vec<T>
}

impl<R: Rng, T> IntoSelectIter<R, T> {
    pub fn new(roulette_wheel: RouletteWheel<T>) -> IntoSelectIter<ThreadRng, T> {
        IntoSelectIter::from_rng(roulette_wheel, thread_rng())
    }

    pub fn from_rng(roulette_wheel: RouletteWheel<T>, rng: R) -> IntoSelectIter<R, T> {
        IntoSelectIter {
            distribution_range: Range::new(0.0, 1.0),
            rng: rng,
            total_fitness: roulette_wheel.total_fitness,
            fitnesses: roulette_wheel.fitnesses,
            population: roulette_wheel.population
        }
    }
}

impl<R: Rng, T> Iterator for IntoSelectIter<R, T> {
    type Item = (f32, T);

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.fitnesses.len(), Some(self.fitnesses.len()))
    }

    fn next(&mut self) -> Option<Self::Item> {
        if !self.fitnesses.is_empty() {
            let sample = self.distribution_range.ind_sample(&mut self.rng);
            let mut selection = sample * self.total_fitness;
            let index = self.fitnesses.iter().position(|fit| {
                            selection -= *fit;
                            selection <= 0.0
                        }).unwrap();
            let fitness = self.fitnesses.swap_remove(index);
            let individual = self.population.swap_remove(index);
            self.total_fitness -= fitness;
            Some((fitness, individual))
        }
        else { None }
    }
}

#[cfg(test)]
mod tests {
    use rand::SeedableRng;
    use rand::StdRng;
    use {RouletteWheel, SelectIter};

    const SEED: [usize; 4] = [4, 2, 42, 4242];

    #[test]
    fn select_iter_seeded() {
        let rng = StdRng::from_seed(&SEED);

        let fitnesses = [0.1, 0.2, 0.3, 0.4, 0.5];
        let fitnesses = fitnesses.iter().cloned();
        let population = 15..20;
        let rw: RouletteWheel<_> = fitnesses.zip(population).collect();

        let mut iter = SelectIter::from_rng(&rw, rng);

        assert_eq!(iter.next(), Some((0.5, &19)));
        assert_eq!(iter.next(), Some((0.3, &17)));
        assert_eq!(iter.next(), Some((0.4, &18)));
        assert_eq!(iter.next(), Some((0.2, &16)));
        assert_eq!(iter.next(), Some((0.1, &15)));
    }
}
<commit_msg>tests: Add a IntoSelectIter test<commit_after>//! A Little implementation of the roulette-wheel principle, `RouletteWheel<T>`.
//! https://wikipedia.org/wiki/Fitness_proportionate_selection
//!
//! ![Fitness proportionate selection](https://upload.wikimedia.org/wikipedia/commons/2/2a/Fitness_proportionate_selection_example.png)
//!
//! # Usage
//!
//! # Examples
//!
//! You can explicitly create a `RouletteWheel<T>` with `new()`:
//!
//! ```
//! use roulette_wheel::RouletteWheel;
//!
//! let rw: RouletteWheel<u8> = RouletteWheel::new();
//! ```
//!
//! You can `push` values in the roulette-wheel (which will grow the wheel as needed):
//! ```
//! use roulette_wheel::RouletteWheel;
//!
//! let mut rw = RouletteWheel::new();
//!
//! rw.push(5., 'a');
//! rw.push(1., 'b');
//!
//! // .iter() will not consume the roulette wheel
//! for (fit, &ind) in rw.iter() {
//!    // do things with individuals here
//! }
//!
//! // .into_iter() consume the roulette wheel
//! for (fit, ind) in rw.into_iter() {
//!     // do things with individuals here
//! }
//!
//! ```

extern crate rand;

use std::iter::{FromIterator, Iterator, IntoIterator};
use rand::{Rng, ThreadRng, thread_rng};
use rand::distributions::{Range, IndependentSample};

/// A roulette-wheel container
pub struct RouletteWheel<T> {
    total_fitness: f32,
    fitnesses: Vec<f32>,
    population: Vec<T>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: self.total_fitness,
            fitnesses: self.fitnesses.clone(),
            population: self.population.clone()
        }
    }
}

impl<T> FromIterator<(f32, T)> for RouletteWheel<T> {
    fn from_iter<A>(iter: A) -> Self where A: IntoIterator<Item=(f32, T)> {
        let iter = iter.into_iter();
        let (lower, _) = iter.size_hint();

        let mut total_fitness = 0.0;
        let mut fitnesses = Vec::with_capacity(lower);
        let mut population = Vec::with_capacity(lower);

        for (fitness, individual) in iter {
            total_fitness += fitness;
            fitnesses.push(fitness);
            population.push(individual);
        }

        RouletteWheel {
            total_fitness: total_fitness,
            fitnesses: fitnesses,
            population: population
        }

        // #![feature(field_init_shorthand)]
        // RouletteWheel { total_fitness, fitnesses, population }
    }
}

impl<T> RouletteWheel<T> {
    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw = RouletteWheel::<u8>::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::new(),
            population: Vec::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw = RouletteWheel::<u8>::with_capacity(15);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(cap: usize) -> RouletteWheel<T> {
        RouletteWheel {
            total_fitness: 0.0,
            fitnesses: Vec::with_capacity(cap),
            population: Vec::with_capacity(cap)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::<u8>::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.fitnesses.reserve(additional);
        self.population.reserve(additional);
    }

    /// Returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.population.len()
    }

    /// Returns `true` if empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let empty_rw = RouletteWheel::<u8>::new();
    ///
    /// assert_eq!(empty_rw.is_empty(), true);
    ///
    /// let non_empty_rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(non_empty_rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.population.is_empty()
    }

    /// Remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw: RouletteWheel<_> = [(0.1, 10), (0.2, 15), (0.5, 20)].iter().cloned().collect();
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.fitnesses.clear();
        self.population.clear();
    }

    /// Add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, fitness: f32, individual: T) {
        assert!(fitness >= 0.0, "Can't push the less than zero fitness: {:?}", fitness);
        assert!((self.total_fitness + fitness).is_finite(), "Fitnesses sum reached a non-finite value!");
        unsafe { self.unchecked_push(fitness, individual) }
    }

    /// Add an element associated with a probability.
    /// This unsafe function doesn't check for total fitness overflow
    /// nether fitness positivity.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// unsafe { rw.unchecked_push(1.0, 'r') };
    /// unsafe { rw.unchecked_push(1.0, 'c') };
    /// unsafe { rw.unchecked_push(1.0, 'a') };
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub unsafe fn unchecked_push(&mut self, fitness: f32, individual: T) {
        self.total_fitness += fitness;
        self.fitnesses.push(fitness);
        self.population.push(individual);
    }

    /// Returns the sum of all individual fitnesses.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(3.0, 'r');
    /// rw.push(2.0, 'c');
    /// rw.push(1.5, 'a');
    ///
    /// assert_eq!(rw.total_fitness(), 6.5);
    /// ```
    pub fn total_fitness(&self) -> f32 {
        self.total_fitness
    }

    pub fn select_iter(&self) -> SelectIter<ThreadRng, T> {
        SelectIter::<ThreadRng, _>::new(&self)
    }
}

pub struct SelectIter<'a, R: Rng, T: 'a> {
    distribution_range: Range<f32>,
    rng: R,
    total_fitness: f32,
    fitnesses_ids: Vec<(usize, f32)>,
    roulette_wheel: &'a RouletteWheel<T>
}

impl<'a, R: Rng, T> SelectIter<'a, R, T> {
    pub fn new(roulette_wheel: &'a RouletteWheel<T>) -> SelectIter<'a, ThreadRng, T> {
        SelectIter::from_rng(roulette_wheel, thread_rng())
    }

    pub fn from_rng(roulette_wheel: &'a RouletteWheel<T>, rng: R) -> SelectIter<'a, R, T> {
        SelectIter {
            distribution_range: Range::new(0.0, 1.0),
            rng: rng,
            total_fitness: roulette_wheel.total_fitness,
            fitnesses_ids: roulette_wheel.fitnesses.iter().cloned().enumerate().collect(),
            roulette_wheel: roulette_wheel
        }
    }
}

impl<'a, R: Rng, T: 'a> Iterator for SelectIter<'a, R, T> {
    type Item = (f32, &'a T);

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.fitnesses_ids.len(), Some(self.fitnesses_ids.len()))
    }

    fn next(&mut self) -> Option<Self::Item> {
        if !self.fitnesses_ids.is_empty() {
            let sample = self.distribution_range.ind_sample(&mut self.rng);
            let mut selection = sample * self.total_fitness;
            let index = self.fitnesses_ids.iter().position(|&(_, fit)| {
                            selection -= fit;
                            selection <= 0.0
                        }).unwrap();
            let (index, fitness) = self.fitnesses_ids.swap_remove(index);
            self.total_fitness -= fitness;
            Some((fitness, &self.roulette_wheel.population[index]))
        }
        else { None }
    }
}

impl<T> IntoIterator for RouletteWheel<T> {
    type Item = (f32, T);
    type IntoIter = IntoSelectIter<ThreadRng, T>;

    fn into_iter(self) -> IntoSelectIter<ThreadRng, T> {
        IntoSelectIter::<ThreadRng, _>::new(self)
    }
}

pub struct IntoSelectIter<R: Rng, T> {
    distribution_range: Range<f32>,
    rng: R,
    total_fitness: f32,
    fitnesses: Vec<f32>,
    population: Vec<T>
}

impl<R: Rng, T> IntoSelectIter<R, T> {
    pub fn new(roulette_wheel: RouletteWheel<T>) -> IntoSelectIter<ThreadRng, T> {
        IntoSelectIter::from_rng(roulette_wheel, thread_rng())
    }

    pub fn from_rng(roulette_wheel: RouletteWheel<T>, rng: R) -> IntoSelectIter<R, T> {
        IntoSelectIter {
            distribution_range: Range::new(0.0, 1.0),
            rng: rng,
            total_fitness: roulette_wheel.total_fitness,
            fitnesses: roulette_wheel.fitnesses,
            population: roulette_wheel.population
        }
    }
}

impl<R: Rng, T> Iterator for IntoSelectIter<R, T> {
    type Item = (f32, T);

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.fitnesses.len(), Some(self.fitnesses.len()))
    }

    fn next(&mut self) -> Option<Self::Item> {
        if !self.fitnesses.is_empty() {
            let sample = self.distribution_range.ind_sample(&mut self.rng);
            let mut selection = sample * self.total_fitness;
            let index = self.fitnesses.iter().position(|fit| {
                            selection -= *fit;
                            selection <= 0.0
                        }).unwrap();
            let fitness = self.fitnesses.swap_remove(index);
            let individual = self.population.swap_remove(index);
            self.total_fitness -= fitness;
            Some((fitness, individual))
        }
        else { None }
    }
}

#[cfg(test)]
mod tests {
    use rand::SeedableRng;
    use rand::StdRng;
    use {RouletteWheel, SelectIter, IntoSelectIter};

    const SEED: [usize; 4] = [4, 2, 42, 4242];

    #[test]
    fn select_iter_seeded() {
        let rng = StdRng::from_seed(&SEED);

        let fitnesses = [0.1, 0.2, 0.3, 0.4, 0.5];
        let fitnesses = fitnesses.iter().cloned();
        let population = 15..20;
        let rw: RouletteWheel<_> = fitnesses.zip(population).collect();

        let mut iter = SelectIter::from_rng(&rw, rng);

        assert_eq!(iter.next(), Some((0.5, &19)));
        assert_eq!(iter.next(), Some((0.3, &17)));
        assert_eq!(iter.next(), Some((0.4, &18)));
        assert_eq!(iter.next(), Some((0.2, &16)));
        assert_eq!(iter.next(), Some((0.1, &15)));
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn into_select_iter_seeded() {
        let rng = StdRng::from_seed(&SEED);

        let fitnesses = [0.1, 0.2, 0.3, 0.4, 0.5];
        let fitnesses = fitnesses.iter().cloned();
        let population = 15..20;
        let rw: RouletteWheel<_> = fitnesses.zip(population).collect();

        let mut iter = IntoSelectIter::from_rng(rw, rng);

        assert_eq!(iter.next(), Some((0.5, 19)));
        assert_eq!(iter.next(), Some((0.3, 17)));
        assert_eq!(iter.next(), Some((0.4, 18)));
        assert_eq!(iter.next(), Some((0.2, 16)));
        assert_eq!(iter.next(), Some((0.1, 15)));
        assert_eq!(iter.next(), None);
    }
}
<|endoftext|>


<commit_before>//! An element-tree style XML library
//!
//! # Examples
//!
//! ```
//! use treexml::Document;
//!
//! let doc_raw = r#"
//! <?xml version="1.1" encoding="UTF-8"?>
//! <table>
//!     <fruit type="apple">worm</fruit>
//!     <vegetable />
//! </table>
//! "#;
//!
//! let doc = Document::parse(doc_raw.as_bytes()).unwrap();
//! let root = doc.root.unwrap();
//!
//! let fruit = root.find_child(|tag| tag.name == "fruit").unwrap().clone();
//! println!("{} [{:?}] = {}", fruit.name, fruit.attributes, fruit.contents.unwrap());
//! ```

extern crate xml;

use std::collections::HashMap;
use std::fmt;
use std::io::Read;
use std::iter::Filter;
use std::slice::{Iter, IterMut};

use xml::reader::{EventReader, XmlEvent};

/// The common error type for all XML tree operations
#[derive(Debug)]
pub enum Error {
    /// Error parsing input data into an XML tree
    ParseError(xml::reader::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ParseError(ref e) => e.fmt(f),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseError(ref e) => e.description(),
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::ParseError(err)
    }
}

/// An XML element
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// Tag prefix, used for namespacing: `xsl` in `xsl:for-each`
    pub prefix: Option<String>,
    /// Tag name: `for-each` in `xsl:for-each`
    pub name: String,
    /// Tag attributes
    pub attributes: HashMap<String, String>,
    /// A vector of child elements
    pub children: Vec<Element>,
    /// Contents of the element
    pub contents: Option<String>,
}

/// An XML document
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
    /// Version of the XML document
    pub version: XmlVersion,
    /// Encoding of the XML document
    pub encoding: String,
    /// Root tag of the XML document
    pub root: Option<Element>,
}

/// Enumeration of XML versions
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML Version 1.0
    Version10,
    /// XML Version 1.1
    Version11,
}

impl Default for Element {
    fn default() -> Self {
        Element{
            prefix: None,
            name: "tag".to_owned(),
            attributes: HashMap::new(),
            children: Vec::new(),
            contents: None,
        }
    }
}

impl Element {

    /// Create a new `Element` with the tag name `name`
    pub fn new<S>(name: S) -> Element where S: Into<String> {
        Element{name: name.into(), .. Element::default()}
    }

    /// Find a single child of the current `Element`, given a predicate
    pub fn find_child<P>(&self, predicate: P) -> Option<&Element>
        where P: for<'r> Fn(&'r &Element) -> bool
    {
        self.children.iter().find(predicate)
    }

    /// Find a single child of the current `Element`, given a predicate; returns a mutable borrow
    pub fn find_child_mut<P>(&mut self, predicate: P) -> Option<&mut Element>
        where P: for<'r> FnMut(&'r &mut Element) -> bool
    {
        self.children.iter_mut().find(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate
    pub fn filter_children<P>(&self, predicate: P) -> Filter<Iter<Element>, P>
        where P: for<'r> Fn(&'r &Element) -> bool
    {
        self.children.iter().filter(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate; returns a mutable iterator
    pub fn filter_children_mut<P>(&mut self, predicate: P) -> Filter<IterMut<Element>, P>
        where P: for<'r> FnMut(&'r &mut Element) -> bool
    {
        self.children.iter_mut().filter(predicate)
    }

}

impl Default for Document {
    fn default() -> Self {
        Document{
            version: XmlVersion::Version10,
            encoding: "UTF-8".to_owned(),
            root: None,
        }
    }
}

impl Document {

    /// Create a new `Document` with default values
    pub fn new() -> Document {
        Document{.. Document::default()}
    }

    /// Parse data from a reader to construct an XML document
    ///
    /// # Failures
    ///
    /// Passes any errors that the `xml-rs` library returns up the stack
    pub fn parse<R: Read>(r: R) -> Result<Document, Error> {

        let mut reader = EventReader::new(r);
        let mut doc = Document::new();

        loop {
            let ev = try!(reader.next());
            match ev {
                XmlEvent::StartDocument{version, encoding, ..} => {

                    // xml-rs's XmlVersion doesn't derive Debug *sadface*
                    doc.version = match version {
                        xml::common::XmlVersion::Version10 => XmlVersion::Version10,
                        xml::common::XmlVersion::Version11 => XmlVersion::Version11,
                    };
                    doc.encoding = encoding;

                },
                XmlEvent::StartElement{name, attributes, ..} => {

                    // Start of the root element

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let root = Element{
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        contents: None,
                    };
                    doc.root = Some(try!(Document::parse_children(&mut reader, root)));

                },
                XmlEvent::EndDocument => break,
                _ => {},
            }
        }

        Ok(doc)

    }

    /// Internal recursive function to parse children of `element`
    fn parse_children<R: Read>(mut reader: &mut EventReader<R>, element: Element) -> Result<Element, Error> {

        let mut me = element.clone();

        loop {
            let ev = try!(reader.next());
            match ev {
                XmlEvent::StartElement{name, attributes, ..} => {

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let child = Element{
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        contents: None
                    };
                    me.children.push(try!(Document::parse_children(&mut reader, child)));

                },
                XmlEvent::EndElement{name} => {

                    if name.prefix == me.prefix && name.local_name == me.name {
                        return Ok(me);
                    } else {
                        // This should never happen, since the base xml library will panic first
                        panic!("Unexpected closing tag: {}, expected {}", name, element.name);
                    }

                },
                XmlEvent::Characters(s) => {

                    let contents = match me.contents {
                        Some(v) => v,
                        None => String::new(),
                    };
                    me.contents = Some(contents + &s)

                },
                XmlEvent::CData(s) => {

                    let contents = match me.contents {
                        Some(v) => v,
                        None => String::new(),
                    };
                    me.contents = Some(contents + "<![CDATA[" + &s + "]]>");

                },
                XmlEvent::Whitespace(_) => {},
                XmlEvent::Comment(_) => {},
                _ => {},
            }
        }
    }

}
<commit_msg>implement Into and From for XmlVersion<commit_after>//! An element-tree style XML library
//!
//! # Examples
//!
//! ```
//! use treexml::Document;
//!
//! let doc_raw = r#"
//! <?xml version="1.1" encoding="UTF-8"?>
//! <table>
//!     <fruit type="apple">worm</fruit>
//!     <vegetable />
//! </table>
//! "#;
//!
//! let doc = Document::parse(doc_raw.as_bytes()).unwrap();
//! let root = doc.root.unwrap();
//!
//! let fruit = root.find_child(|tag| tag.name == "fruit").unwrap().clone();
//! println!("{} [{:?}] = {}", fruit.name, fruit.attributes, fruit.contents.unwrap());
//! ```

extern crate xml;

use std::collections::HashMap;
use std::fmt;
use std::io::Read;
use std::iter::Filter;
use std::slice::{Iter, IterMut};

/// The common error type for all XML tree operations
#[derive(Debug)]
pub enum Error {
    /// Error parsing input data into an XML tree
    ParseError(xml::reader::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ParseError(ref e) => e.fmt(f),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseError(ref e) => e.description(),
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::ParseError(err)
    }
}

/// Enumeration of XML versions
///
/// This exists solely because `xml-rs`'s XmlVersion doesn't implement Debug
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML Version 1.0
    Version10,
    /// XML Version 1.1
    Version11,
}

impl From<xml::common::XmlVersion> for XmlVersion {
    fn from(v: xml::common::XmlVersion) -> XmlVersion {
        match v {
            xml::common::XmlVersion::Version10 => XmlVersion::Version10,
            xml::common::XmlVersion::Version11 => XmlVersion::Version11,
        }
    }
}

impl Into<xml::common::XmlVersion> for XmlVersion {
    fn into(self) -> xml::common::XmlVersion {
        match self {
            XmlVersion::Version10 => xml::common::XmlVersion::Version10,
            XmlVersion::Version11 => xml::common::XmlVersion::Version11,
        }
    }
}

/// An XML element
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// Tag prefix, used for namespacing: `xsl` in `xsl:for-each`
    pub prefix: Option<String>,
    /// Tag name: `for-each` in `xsl:for-each`
    pub name: String,
    /// Tag attributes
    pub attributes: HashMap<String, String>,
    /// A vector of child elements
    pub children: Vec<Element>,
    /// Contents of the element
    pub contents: Option<String>,
}

impl Default for Element {
    fn default() -> Self {
        Element{
            prefix: None,
            name: "tag".to_owned(),
            attributes: HashMap::new(),
            children: Vec::new(),
            contents: None,
        }
    }
}

impl Element {

    /// Create a new `Element` with the tag name `name`
    pub fn new<S>(name: S) -> Element
        where S: Into<String>
    {
        Element{name: name.into(), .. Element::default()}
    }

    /// Find a single child of the current `Element`, given a predicate
    pub fn find_child<P>(&self, predicate: P) -> Option<&Element>
        where P: for<'r> Fn(&'r &Element) -> bool
    {
        self.children.iter().find(predicate)
    }

    /// Find a single child of the current `Element`, given a predicate; returns a mutable borrow
    pub fn find_child_mut<P>(&mut self, predicate: P) -> Option<&mut Element>
        where P: for<'r> FnMut(&'r &mut Element) -> bool
    {
        self.children.iter_mut().find(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate
    pub fn filter_children<P>(&self, predicate: P) -> Filter<Iter<Element>, P>
        where P: for<'r> Fn(&'r &Element) -> bool
    {
        self.children.iter().filter(predicate)
    }

    /// Filters the children of the current `Element`, given a predicate; returns a mutable iterator
    pub fn filter_children_mut<P>(&mut self, predicate: P) -> Filter<IterMut<Element>, P>
        where P: for<'r> FnMut(&'r &mut Element) -> bool
    {
        self.children.iter_mut().filter(predicate)
    }

}

/// An XML document
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
    /// Version of the XML document
    pub version: XmlVersion,
    /// Encoding of the XML document
    pub encoding: String,
    /// Root tag of the XML document
    pub root: Option<Element>,
}

impl Default for Document {
    fn default() -> Self {
        Document{
            version: XmlVersion::Version10,
            encoding: "UTF-8".to_owned(),
            root: None,
        }
    }
}

impl Document {

    /// Create a new `Document` with default values
    pub fn new() -> Document {
        Document{.. Document::default()}
    }

    /// Parse data from a reader to construct an XML document
    ///
    /// # Failures
    ///
    /// Passes any errors that the `xml-rs` library returns up the stack
    pub fn parse<R: Read>(r: R) -> Result<Document, Error> {

        use xml::reader::{EventReader, XmlEvent};

        let mut reader = EventReader::new(r);
        let mut doc = Document::new();

        loop {
            let ev = try!(reader.next());
            match ev {
                XmlEvent::StartDocument{version, encoding, ..} => {
                    doc.version = XmlVersion::from(version);
                    doc.encoding = encoding;
                },
                XmlEvent::StartElement{name, attributes, ..} => {

                    // Start of the root element

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let root = Element{
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        contents: None,
                    };
                    doc.root = Some(try!(Document::parse_children(&mut reader, root)));

                },
                XmlEvent::EndDocument => break,
                _ => {},
            }
        }

        Ok(doc)

    }

    /// Internal recursive function to parse children of `element`
    fn parse_children<R: Read>(mut reader: &mut xml::reader::EventReader<R>, element: Element) -> Result<Element, Error> {

        use xml::reader::XmlEvent;

        let mut me = element.clone();

        loop {
            let ev = try!(reader.next());
            match ev {
                XmlEvent::StartElement{name, attributes, ..} => {

                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        let attr_name = match attr.name.prefix {
                            Some(prefix) => format!("{}:{}", prefix, attr.name.local_name),
                            None => attr.name.local_name,
                        };
                        attr_map.insert(attr_name, attr.value);
                    }

                    let child = Element{
                        prefix: name.prefix,
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        contents: None
                    };
                    me.children.push(try!(Document::parse_children(&mut reader, child)));

                },
                XmlEvent::EndElement{name} => {

                    if name.prefix == me.prefix && name.local_name == me.name {
                        return Ok(me);
                    } else {
                        // This should never happen, since the base xml library will panic first
                        panic!("Unexpected closing tag: {}, expected {}", name, element.name);
                    }

                },
                XmlEvent::Characters(s) => {

                    let contents = match me.contents {
                        Some(v) => v,
                        None => String::new(),
                    };
                    me.contents = Some(contents + &s)

                },
                XmlEvent::CData(s) => {

                    let contents = match me.contents {
                        Some(v) => v,
                        None => String::new(),
                    };
                    me.contents = Some(contents + "<![CDATA[" + &s + "]]>");

                },
                XmlEvent::Whitespace(_) => {},
                XmlEvent::Comment(_) => {},
                _ => {},
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int, strlen};
use std::ffi::{NulError, CString, CStr};
use std::string::FromUtf8Error;

const MAX_USERNAME: c_int = 256;

fn c_to_string(raw: *const c_char) -> Option<String> {
    std::str::from_utf8(unsafe{CStr::from_ptr(raw)}.to_bytes())
        .ok()
        .map(|o| o.to_string())
}

#[derive(Debug)]
pub enum Error {
    Krb5(Krb5Error),
    FromUtf8(FromUtf8Error),
    Nul(NulError),
}

#[derive(Debug)]
pub struct Krb5Error {
    major: c_int,
    message: String,
}

impl Krb5Error {
    fn new(major: c_int) -> Krb5Error {
        let message = format!("Kerberos Error: {}", major).to_string();
        Krb5Error{major: major, message: message}
    }
    fn from_context(context: &Context, major: c_int) -> Krb5Error {
        let message = context.error_message(major);
        match message {
            Some(msg) => Krb5Error{major: major, message: msg},
            None => Krb5Error::new(major),
        }
    }
    fn description(&self) -> &str {
        self.message.as_ref()
    }
}

impl std::fmt::Display for Krb5Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::FromUtf8(ref e) => e.fmt(f),
            Error::Nul(ref e) => e.fmt(f),
            Error::Krb5(ref e) => e.fmt(f),
        }
    }
}
impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::FromUtf8(ref e) => e.description(),
            Error::Nul(ref e) => e.description(),
            Error::Krb5(ref e) => e.description(),
        }
    }
    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::FromUtf8(ref e) => Some(e as &std::error::Error),
            Error::Nul(ref e) => Some(e as &std::error::Error),
            Error::Krb5(_) => None,
        }
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Error {
        Error::Nul(e)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(e: FromUtf8Error) -> Error {
        Error::FromUtf8(e)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

// From krb5.h:
//  struct _krb5_context;
//  typedef struct _krb5_context * krb5_context;
//  This is opaque in the c header file.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_context;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Context {
    ctx: *mut krb5_context,
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe{
            krb5_free_context(self.ctx)
        }
    }
}

impl Context {
    pub fn new() -> Result<Context> {
        let mut kcontext: *mut krb5_context = std::ptr::null_mut();
        let err = unsafe {krb5_init_context(&mut kcontext)};
        if err == 0 {
            Ok(Context{ctx: kcontext})
        } else {
            Err(Error::Krb5(Krb5Error::new(err)))
        }
    }

    fn error_message(&self, code: c_int) -> Option<String> {
        let raw = unsafe{krb5_get_error_message(self.ctx, code)};
        unsafe{krb5_clear_error_message(self.ctx)};
        let res = c_to_string(raw);
        unsafe{krb5_free_error_message(self.ctx, raw)};
        res
    }

    // TODO: evaluate if it's appropriate to return a CString, an
    // OsString, or something else. It probably doesn't make sense to
    // require Utf8 encoding in this library.
    pub fn localname(&self, name: &str) -> Result<String> {
        let mut princ = Principal::new(self);
        let cname = try!(CString::new(name.as_bytes()));
        let err = unsafe {krb5_parse_name(self.ctx, cname.as_ptr(), &mut princ.princ)};
        if err != 0 {
            return Err(Error::Krb5(Krb5Error::from_context(self, err)))
        }

        let mut lname: Vec<u8> = Vec::with_capacity(MAX_USERNAME as usize);
        unsafe {lname.set_len((MAX_USERNAME - 1) as usize)};
        lname.push('\0' as u8);
        let err = unsafe {krb5_aname_to_localname(self.ctx,
                                                  princ.princ,
                                                  MAX_USERNAME - 1,
                                                  &mut lname[..])};
        if err != 0 {
            return Err(Error::Krb5(Krb5Error::from_context(self, err)));
        }

        // Need to find the length (position of the NUL put in place by
        // krb5_aname_to_lname to indicate the end of the string and
        // truncate the Vec<u8> to that size so that we can convert it
        // it to a String
        let len = unsafe {strlen(lname.as_ptr() as *const i8)};
        lname.truncate(len as usize);

        Ok(try!(String::from_utf8(lname)))
    }
}

// TODO: Is there any reason to actually expose the internals of
// krb5_principal? If so we'll have to fill in the internals.
// From krb5.h:
//  typedef struct krb5_principal_data {
//      krb5_magic magic;
//      krb5_data realm;
//      krb5_data *data;            /**< An array of strings */
//      krb5_int32 length;
//      krb5_int32 type;
//  } krb5_principal_data;
//  typedef krb5_principal_data * krb5_principal;
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_principal;
pub struct Principal<'a> {
    princ: *mut krb5_principal,
    ctx: &'a Context,
}

impl<'a> Principal<'a> {
    // TODO: Should the constructor take a principal name and handle
    // calling krb5_parse_name for it? Should it not require a Context
    // to be passed in, and initialize one?
    fn new(ctx: &Context) -> Principal {
        Principal{princ: std::ptr::null_mut(), ctx: ctx}
    }
}

impl<'a> Drop for Principal<'a> {
    fn drop(&mut self) {
        unsafe {krb5_free_principal(self.ctx.ctx, self.princ)}
    }
}

#[link(name = "krb5")]
extern "C" {
    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_init_context(krb5_context *context);
    fn krb5_init_context(context: *mut *mut krb5_context) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_context(krb5_context context);
    fn krb5_free_context(context: *mut krb5_context);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_parse_name(krb5_context context,
    //                  const char *name,
    //                  krb5_principal *nprincipal);
    fn krb5_parse_name(context: *mut krb5_context,
                       name: *const c_char,
                       principal: *mut *mut krb5_principal) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_principal(krb5_context context,
    //                      krb5_principal val);
    fn krb5_free_principal(context: *mut krb5_context,
                           val: *mut krb5_principal);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_aname_to_localname(krb5_context context,
    //                          krb5_const_principal aname,
    //                          int lnsize_in,
    //                          char *lname);
    fn krb5_aname_to_localname(context: *mut krb5_context,
                               aname: *mut krb5_principal,
                               size: c_int,
                               lname: *mut [u8]) -> c_int;

    // From krb5.h:
    //   const char * KRB5_CALLCONV
    //   krb5_get_error_message(krb5_context ctx,
    //                          krb5_error_code code);
    fn krb5_get_error_message(context: *mut krb5_context,
                              code: c_int) -> *const c_char;

    // From krb5.h:
    //   void KRB5_CALLCONV
    //   krb5_clear_error_message(krb5_context ctx);
    fn krb5_clear_error_message(context: *mut krb5_context);

    // From krb5.h:
    //   void KRB5_CALLCONV
    //   krb5_free_error_message(krb5_context ctx,
    //                           const char *msg);
    fn krb5_free_error_message(context: *mut krb5_context,
                               message: *const c_char);
}
<commit_msg>Be unnecessarily pedantic<commit_after>extern crate libc;

use libc::{c_char, c_int, strlen};
use std::ffi::{NulError, CString, CStr};
use std::string::FromUtf8Error;

const MAX_USERNAME: c_int = 256;

fn c_to_string(raw: *const c_char) -> Option<String> {
    std::str::from_utf8(unsafe{CStr::from_ptr(raw)}.to_bytes())
        .ok()
        .map(|o| o.to_string())
}

#[derive(Debug)]
pub enum Error {
    Krb5(Krb5Error),
    FromUtf8(FromUtf8Error),
    Nul(NulError),
}

#[derive(Debug)]
pub struct Krb5Error {
    major: c_int,
    message: String,
}

impl Krb5Error {
    fn new(major: c_int) -> Krb5Error {
        let message = format!("Kerberos Error: {}", major).to_string();
        Krb5Error{major: major, message: message}
    }
    fn from_context(context: &Context, major: c_int) -> Krb5Error {
        let message = context.error_message(major);
        match message {
            Some(msg) => Krb5Error{major: major, message: msg},
            None => Krb5Error::new(major),
        }
    }
    fn description(&self) -> &str {
        self.message.as_ref()
    }
}

impl std::fmt::Display for Krb5Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::FromUtf8(ref e) => e.fmt(f),
            Error::Nul(ref e) => e.fmt(f),
            Error::Krb5(ref e) => e.fmt(f),
        }
    }
}
impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::FromUtf8(ref e) => e.description(),
            Error::Nul(ref e) => e.description(),
            Error::Krb5(ref e) => e.description(),
        }
    }
    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::FromUtf8(ref e) => Some(e as &std::error::Error),
            Error::Nul(ref e) => Some(e as &std::error::Error),
            Error::Krb5(_) => None,
        }
    }
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Error {
        Error::Nul(e)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(e: FromUtf8Error) -> Error {
        Error::FromUtf8(e)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

// From krb5.h:
//  struct _krb5_context;
//  typedef struct _krb5_context * krb5_context;
//  This is opaque in the c header file.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_context;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Context {
    ctx: *mut krb5_context,
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe{
            krb5_free_context(self.ctx)
        }
    }
}

impl Context {
    pub fn new() -> Result<Context> {
        let mut kcontext: *mut krb5_context = std::ptr::null_mut();
        let err = unsafe {krb5_init_context(&mut kcontext)};
        if err == 0 {
            Ok(Context{ctx: kcontext})
        } else {
            Err(Error::Krb5(Krb5Error::new(err)))
        }
    }

    fn error_message(&self, code: c_int) -> Option<String> {
        let raw = unsafe{krb5_get_error_message(self.ctx, code)};
        unsafe{krb5_clear_error_message(self.ctx)};
        let res = c_to_string(raw);
        unsafe{krb5_free_error_message(self.ctx, raw)};
        res
    }

    // TODO: evaluate if it's appropriate to return a CString, an
    // OsString, or something else. It probably doesn't make sense to
    // require Utf8 encoding in this library.
    pub fn localname(&self, name: &str) -> Result<String> {
        let mut princ = Principal::new(self);
        let cname = try!(CString::new(name.as_bytes()));
        let err = unsafe {krb5_parse_name(self.ctx, cname.as_ptr(), &mut princ.princ)};
        if err != 0 {
            return Err(Error::Krb5(Krb5Error::from_context(self, err)))
        }

        let mut lname: Vec<u8> = Vec::with_capacity(MAX_USERNAME as usize);
        unsafe {lname.set_len((MAX_USERNAME - 1) as usize)};
        lname.push('\0' as u8);
        let err = unsafe {krb5_aname_to_localname(self.ctx,
                                                  princ.princ,
                                                  MAX_USERNAME - 1,
                                                  &mut lname[..])};
        if err != 0 {
            return Err(Error::Krb5(Krb5Error::from_context(self, err)));
        }

        // Need to find the length (position of the NUL put in place by
        // krb5_aname_to_lname to indicate the end of the string and
        // truncate the Vec<u8> to that size so that we can convert it
        // it to a String
        let len = unsafe {strlen(lname.as_ptr() as *const i8)};
        lname.truncate(len as usize);

        Ok(try!(String::from_utf8(lname)))
    }
}

// TODO: Is there any reason to actually expose the internals of
// krb5_principal? If so we'll have to fill in the internals.
// From krb5.h:
//  typedef struct krb5_principal_data {
//      krb5_magic magic;
//      krb5_data realm;
//      krb5_data *data;            /**< An array of strings */
//      krb5_int32 length;
//      krb5_int32 type;
//  } krb5_principal_data;
//  typedef krb5_principal_data * krb5_principal;
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_principal;
pub struct Principal<'a> {
    princ: *mut krb5_principal,
    ctx: &'a Context,
}

impl<'a> Principal<'a> {
    // TODO: Should the constructor take a principal name and handle
    // calling krb5_parse_name for it? Should it not require a Context
    // to be passed in, and initialize one?
    fn new(ctx: &Context) -> Principal {
        Principal{princ: std::ptr::null_mut(), ctx: ctx}
    }
}

impl<'a> Drop for Principal<'a> {
    fn drop(&mut self) {
        unsafe {krb5_free_principal(self.ctx.ctx, self.princ)}
    }
}

#[link(name = "krb5")]
extern "C" {
    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_init_context(krb5_context *context);
    fn krb5_init_context(context: *mut *mut krb5_context) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_context(krb5_context context);
    fn krb5_free_context(context: *mut krb5_context);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_parse_name(krb5_context context,
    //                  const char *name,
    //                  krb5_principal *nprincipal);
    fn krb5_parse_name(context: *mut krb5_context,
                       name: *const c_char,
                       principal: *mut *mut krb5_principal) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_principal(krb5_context context,
    //                      krb5_principal val);
    fn krb5_free_principal(context: *mut krb5_context,
                           val: *mut krb5_principal);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_aname_to_localname(krb5_context context,
    //                          krb5_const_principal aname,
    //                          int lnsize_in,
    //                          char *lname);
    fn krb5_aname_to_localname(context: *mut krb5_context,
                               aname: *mut krb5_principal,
                               size: c_int,
                               lname: *mut [u8]) -> c_int;

    // From krb5.h:
    //  const char * KRB5_CALLCONV
    //  krb5_get_error_message(krb5_context ctx,
    //                         krb5_error_code code);
    fn krb5_get_error_message(context: *mut krb5_context,
                              code: c_int) -> *const c_char;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_clear_error_message(krb5_context ctx);
    fn krb5_clear_error_message(context: *mut krb5_context);

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_error_message(krb5_context ctx,
    //                          const char *msg);
    fn krb5_free_error_message(context: *mut krb5_context,
                               message: *const c_char);
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::c_void;

mod ffi;

pub use self::ffi::Align;
pub use self::ffi::Dimensions;
pub use self::ffi::Direction;
pub use self::ffi::Edge;
pub use self::ffi::ExperimentalFeature;
pub use self::ffi::FlexDirection;
pub use self::ffi::FlexWrap;
pub use self::ffi::JustifyContent;
pub use self::ffi::LogLevel;
pub use self::ffi::MeasureMode;
pub use self::ffi::Overflow;
pub use self::ffi::PositionType;
pub use self::ffi::PrintOptions;
pub use self::ffi::Size;

pub struct Context<'a> {
    pub text: &'a str,
}

impl<'a> Context<'a> {
    pub fn new(text: &'a str) -> Context<'a> {
        Context { text: text }
    }

    pub fn get_text(&self) -> &'a str {
        self.text
    }
}

pub extern "C" fn measure(node: *mut ffi::Node,
                          width: f32,
                          width_mode: MeasureMode,
                          height: f32,
                          height_mode: MeasureMode)
                          -> Size {
    let n = Node { _node: node };
    let width = n.get_context().get_text().len() as f32;

    // n is only made a Node to get at context.
    // we want to keep node passed in around
    // so don't run Drop at end of method
    // it'll Drop elsewhere
    std::mem::forget(n);

    Size {
        width: width,
        height: 1.0,
    }
}

#[derive(Debug)]
pub struct Node {
    _node: *mut ffi::Node,
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

impl std::ops::Drop for Node {
    fn drop(&mut self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Node;
    use measure;

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!"));
        let context = node.get_context();
        assert!(context.get_text() == "Yo!");
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!"));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
    }
}
<commit_msg>fix(Drop): drop Drop for now<commit_after>extern crate libc;

use libc::c_void;

mod ffi;

pub use self::ffi::Align;
pub use self::ffi::Dimensions;
pub use self::ffi::Direction;
pub use self::ffi::Edge;
pub use self::ffi::ExperimentalFeature;
pub use self::ffi::FlexDirection;
pub use self::ffi::FlexWrap;
pub use self::ffi::JustifyContent;
pub use self::ffi::LogLevel;
pub use self::ffi::MeasureMode;
pub use self::ffi::Overflow;
pub use self::ffi::PositionType;
pub use self::ffi::PrintOptions;
pub use self::ffi::Size;

pub struct Context<'a> {
    pub text: &'a str,
}

impl<'a> Context<'a> {
    pub fn new(text: &'a str) -> Context<'a> {
        Context { text: text }
    }

    pub fn get_text(&self) -> &'a str {
        self.text
    }
}

pub extern "C" fn measure(node: *mut ffi::Node,
                          width: f32,
                          width_mode: MeasureMode,
                          height: f32,
                          height_mode: MeasureMode)
                          -> Size {
    let n = Node { _node: node };
    let width = n.get_context().get_text().len() as f32;

    Size {
        width: width,
        height: 1.0,
    }
}

#[derive(Debug)]
pub struct Node {
    _node: *mut ffi::Node,
}

impl Node {
    pub fn new() -> Node {
        Node { _node: unsafe { ffi::YGNodeNew() } }
    }

    pub fn get_instance_count() -> i32 {
        unsafe { ffi::YGNodeGetInstanceCount() }
    }

    pub fn reset(&mut self) {
        unsafe { ffi::YGNodeReset(self._node) }
    }

    pub fn free(self) {
        unsafe { ffi::YGNodeFree(self._node) }
    }

    pub fn free_recursive(self) {
        unsafe { ffi::YGNodeFreeRecursive(self._node) }
    }

    pub fn set_direction(&mut self, value: ffi::Direction) {
        unsafe { ffi::YGNodeStyleSetDirection(self._node, value) }
    }

    pub fn get_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeStyleGetDirection(self._node) }
    }

    pub fn set_flex_direction(&mut self, value: ffi::FlexDirection) {
        unsafe { ffi::YGNodeStyleSetFlexDirection(self._node, value) }
    }

    pub fn get_flex_direction(&self) -> ffi::FlexDirection {
        unsafe { ffi::YGNodeStyleGetFlexDirection(self._node) }
    }

    pub fn set_width(&mut self, width: f32) {
        unsafe { ffi::YGNodeStyleSetWidth(self._node, width) }
    }

    pub fn get_width(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetWidth(self._node) }
    }

    pub fn set_height(&mut self, height: f32) {
        unsafe { ffi::YGNodeStyleSetHeight(self._node, height) }
    }

    pub fn get_height(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetHeight(self._node) }
    }

    pub fn calculate_layout(&mut self) {
        unsafe {
            ffi::YGNodeCalculateLayout(self._node, std::f32::NAN, std::f32::NAN, Direction::LTR)
        }
    }

    pub fn get_layout_width(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetWidth(self._node) }
    }

    pub fn get_layout_height(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetHeight(self._node) }
    }

    pub fn get_layout_left(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetLeft(self._node) }
    }

    pub fn get_layout_top(&self) -> f32 {
        unsafe { ffi::YGNodeLayoutGetTop(self._node) }
    }

    pub fn get_layout_direction(&self) -> ffi::Direction {
        unsafe { ffi::YGNodeLayoutGetDirection(self._node) }
    }

    pub fn insert_child(&mut self, child: &Node, index: u32) {
        unsafe { ffi::YGNodeInsertChild(self._node, child._node, index) }
    }

    pub fn remove_child(&mut self, child: &Node) {
        unsafe { ffi::YGNodeRemoveChild(self._node, child._node) }
    }

    pub fn get_child(&self, index: u32) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetChild(self._node, index) } }
    }

    pub fn get_child_count(&self) -> u32 {
        unsafe { ffi::YGNodeGetChildCount(self._node) }
    }

    pub fn get_parent(&self) -> Node {
        unsafe { Node { _node: ffi::YGNodeGetParent(self._node) } }
    }

    pub fn set_justify_content(&mut self, value: ffi::JustifyContent) {
        unsafe { ffi::YGNodeStyleSetJustifyContent(self._node, value) }
    }

    pub fn get_justify_content(&self) -> ffi::JustifyContent {
        unsafe { ffi::YGNodeStyleGetJustifyContent(self._node) }
    }

    pub fn get_align_items(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignItems(self._node) }
    }

    pub fn set_align_items(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignItems(self._node, value) }
    }

    pub fn get_align_self(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignSelf(self._node) }
    }

    pub fn set_align_self(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignSelf(self._node, value) }
    }

    pub fn get_align_content(&self) -> ffi::Align {
        unsafe { ffi::YGNodeStyleGetAlignContent(self._node) }
    }

    pub fn set_align_content(&mut self, value: ffi::Align) {
        unsafe { ffi::YGNodeStyleSetAlignContent(self._node, value) }
    }

    pub fn get_position_type(&self) -> ffi::PositionType {
        unsafe { ffi::YGNodeStyleGetPositionType(self._node) }
    }

    pub fn set_position_type(&mut self, value: ffi::PositionType) {
        unsafe { ffi::YGNodeStyleSetPositionType(self._node, value) }
    }

    pub fn get_flex_wrap(&self) -> ffi::FlexWrap {
        unsafe { ffi::YGNodeStyleGetFlexWrap(self._node) }
    }

    pub fn set_flex_wrap(&mut self, value: ffi::FlexWrap) {
        unsafe { ffi::YGNodeStyleSetFlexWrap(self._node, value) }
    }

    pub fn get_overflow(&self) -> ffi::Overflow {
        unsafe { ffi::YGNodeStyleGetOverflow(self._node) }
    }

    pub fn set_overflow(&mut self, value: ffi::Overflow) {
        unsafe { ffi::YGNodeStyleSetOverflow(self._node, value) }
    }

    pub fn set_flex(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlex(self._node, value) }
    }

    pub fn get_flex_grow(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexGrow(self._node) }
    }

    pub fn set_flex_grow(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexGrow(self._node, value) }
    }

    pub fn get_flex_shrink(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexShrink(self._node) }
    }

    pub fn set_flex_shrink(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexShrink(self._node, value) }
    }

    pub fn get_flex_basis(&self) -> f32 {
        unsafe { ffi::YGNodeStyleGetFlexBasis(self._node) }
    }

    pub fn set_flex_basis(&mut self, value: f32) {
        unsafe { ffi::YGNodeStyleSetFlexBasis(self._node, value) }
    }

    pub fn get_margin(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetMargin(self._node, edge) }
    }

    pub fn set_margin(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetMargin(self._node, edge, value) }
    }

    pub fn get_padding(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPadding(self._node, edge) }
    }

    pub fn set_padding(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPadding(self._node, edge, value) }
    }

    pub fn get_border(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetBorder(self._node, edge) }
    }

    pub fn set_border(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetBorder(self._node, edge, value) }
    }

    pub fn get_position(&self, edge: ffi::Edge) -> f32 {
        unsafe { ffi::YGNodeStyleGetPosition(self._node, edge) }
    }

    pub fn set_position(&mut self, edge: ffi::Edge, value: f32) {
        unsafe { ffi::YGNodeStyleSetPosition(self._node, edge, value) }
    }

    pub fn set_measure_func(&mut self,
                            func: extern "C" fn(*mut ffi::Node,
                                                f32,
                                                MeasureMode,
                                                f32,
                                                MeasureMode)
                                                -> Size) {
        unsafe { ffi::YGNodeSetMeasureFunc(self._node, func) }
    }

    pub fn mark_dirty(&mut self) {
        unsafe { ffi::YGNodeMarkDirty(self._node) }
    }

    pub fn is_dirty(&self) -> bool {
        unsafe { ffi::YGNodeIsDirty(self._node) }
    }

    pub fn set_context(&mut self, context: *mut Context) {
        unsafe { ffi::YGNodeSetContext(self._node, context as *mut c_void) }
    }

    pub fn get_context(&self) -> &Context {
        unsafe {
            let context = ffi::YGNodeGetContext(self._node);
            let ref ctx: Context = *(context as *mut Context);
            ctx
        }
    }
}

#[cfg(test)]
mod tests {
    use Context;
    use Node;
    use measure;

    #[test]
    fn dirty_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        assert!(!node.is_dirty());
        node.mark_dirty();
        assert!(node.is_dirty());
        node.free();
    }

    #[test]
    fn context_works() {
        let mut node = Node::new();
        node.set_context(&mut Context::new("Yo!"));
        {
            let context = node.get_context();
            assert!(context.get_text() == "Yo!");
        }
        node.free();
    }

    #[test]
    fn measure_works() {
        let mut node = Node::new();
        node.set_measure_func(measure);
        node.set_context(&mut Context::new("Yo!!"));
        node.calculate_layout();
        assert!(node.get_layout_width() == 4.0);
        assert!(node.get_layout_height() == 1.0);
        node.free();
    }

    #[test]
    fn get_instance_count() {
        assert!(Node::get_instance_count() == 0);
        let mut node = Node::new();
        assert!(Node::get_instance_count() == 1);
        node.free();
        assert!(Node::get_instance_count() == 0);
    }

    #[test]
    fn get_child_count() {
        let mut p1 = Node::new();
        let mut c1 = Node::new();
        let mut c2 = Node::new();
        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);
        assert!(p1.get_child_count() == 2);
        p1.free();
        c1.free();
        c2.free();
    }

    #[test]
    fn get_child() {
        let mut p1 = Node::new();

        let mut c1 = Node::new();
        c1.set_width(1.0);

        let mut c2 = Node::new();
        c2.set_width(2.0);

        p1.insert_child(&c1, 0);
        p1.insert_child(&c2, 1);

        assert!(p1.get_child(0).get_width() == 1.0);
        assert!(p1.get_child(1).get_width() == 2.0);
        p1.free();
        c1.free();
        c2.free();
    }
}
<|endoftext|>


<commit_before>//! # A set of useful simple additional methods
//!
//! Examples:
//!
//! ```rust
//! use moreops::*;
//!
//! // Simple wrapping into Option
//! let some_num = 123.some();
//! let none_num = none::<i32>();
//!
//! // Simple wrapping into Result
//! let ok = 123.ok();
//! let err = "Error!".to_owned().err();
//!
//! // If-like operations with Option
//! let x = 42;
//! let answer = (x % 2 == 0).option("even").unwrap_or("odd");
//!
//! // Tap into some result (like `<|` and `|>` operators from Scalaz)
//! fn f() -> i32 {
//!     123
//! }
//! assert_eq!(f().tap(|x| println!("{:?}", x)), 123);
//! assert_eq!(f().then(|x| x * 2), 246);
//!
//! // Swap result
//! assert_eq!(123.ok().swap(), 123.err());
//! assert_eq!(123.ok().swap().swap(), 123.ok());
//! ```

pub trait OptionOps {
    fn some(self) -> Option<Self> where Self: Sized {
        Some(self)
    }
}

impl<T> OptionOps for T {}

pub fn none<T>() -> Option<T> {
    None
}

pub trait ResultOps<T = ()> {
    fn ok(self) -> Result<Self, T> where Self: Sized {
        Ok(self)
    }

    fn err(self) -> Result<T, Self> where Self: Sized {
        Err(self)
    }
}

impl<T> ResultOps for T {}

pub trait BoolOps {
    fn option<T>(self, x: T) -> Option<T>;
}

impl BoolOps for bool {
    fn option<T>(self, x: T) -> Option<T> {
        if self {
            Some(x)
        } else {
            None
        }
    }
}

pub trait TapOps {
    fn tap<R, F: Fn(&Self) -> R>(self, f: F) -> Self where Self: Sized {
        let _ = f(&self);
        self
    }

    fn then<R, F: FnOnce(Self) -> R>(self, f: F) -> R where Self: Sized {
        f(self)
    }
}

impl<T> TapOps for T {}

pub trait ResultExt<T, E>: Sized {
    fn swap(self) -> Result<E, T>;
}

impl<T, E> ResultExt<T, E> for Result<T, E> {
    fn swap(self) -> Result<E, T> {
        match self {
            Ok(v) => Err(v),
            Err(e) => Ok(e),
        }
    }
}

#[test]
fn it_works() {
    assert_eq!(1.some(), Some(1));
    assert_eq!(none::<i32>(), None);

    assert_eq!(true.option(1), Some(1));
    assert_eq!(false.option(1), None);

    assert_eq!(1.tap(|&n| {
        assert_eq!(n, 1);
        2
    }), 1);

    assert_eq!(123.ok().swap(), 123.err());
}
<commit_msg>add tuple ops<commit_after>//! # A set of useful simple additional methods
//!
//! Examples:
//!
//! ```rust
//! use moreops::*;
//!
//! // Simple wrapping into Option
//! let some_num = 123.some();
//! let none_num = none::<i32>();
//!
//! // Simple wrapping into Result
//! let ok = 123.ok();
//! let err = "Error!".to_owned().err();
//!
//! // If-like operations with Option
//! let x = 42;
//! let answer = (x % 2 == 0).option("even").unwrap_or("odd");
//!
//! // Tap into some result (like `<|` and `|>` operators from Scalaz)
//! fn f() -> i32 {
//!     123
//! }
//! assert_eq!(f().tap(|x| println!("{:?}", x)), 123);
//! assert_eq!(f().then(|x| x * 2), 246);
//!
//! // Swap result
//! assert_eq!(123.ok().swap(), 123.err());
//! assert_eq!(123.ok().swap().swap(), 123.ok());
//!
//! // Wrap into tuple
//! let one = 123.once();
//! let two = 123.twice();
//! let three = 123.thrice();
//! ```

pub trait OptionOps {
    fn some(self) -> Option<Self> where Self: Sized {
        Some(self)
    }
}

impl<T> OptionOps for T {}

pub fn none<T>() -> Option<T> {
    None
}

pub trait ResultOps<T = ()> {
    fn ok(self) -> Result<Self, T> where Self: Sized {
        Ok(self)
    }

    fn err(self) -> Result<T, Self> where Self: Sized {
        Err(self)
    }
}

impl<T> ResultOps for T {}

pub trait BoolOps {
    fn option<T>(self, x: T) -> Option<T>;
}

impl BoolOps for bool {
    fn option<T>(self, x: T) -> Option<T> {
        if self {
            Some(x)
        } else {
            None
        }
    }
}

pub trait TapOps {
    fn tap<R, F: Fn(&Self) -> R>(self, f: F) -> Self where Self: Sized {
        let _ = f(&self);
        self
    }

    fn then<R, F: FnOnce(Self) -> R>(self, f: F) -> R where Self: Sized {
        f(self)
    }
}

impl<T> TapOps for T {}

pub trait TupleOps: Sized {
    fn once(self) -> (Self,) {
        (self,)
    }

    fn twice(self) -> (Self, Self) where Self: Clone {
        (self.clone(), self)
    }

    fn thrice(self) -> (Self, Self, Self) where Self: Clone {
        (self.clone(), self.clone(), self)
    }
}

impl<T> TupleOps for T {}

pub trait ResultExt<T, E>: Sized {
    fn swap(self) -> Result<E, T>;
}

impl<T, E> ResultExt<T, E> for Result<T, E> {
    fn swap(self) -> Result<E, T> {
        match self {
            Ok(v) => Err(v),
            Err(e) => Ok(e),
        }
    }
}

#[test]
fn it_works() {
    assert_eq!(1.some(), Some(1));
    assert_eq!(none::<i32>(), None);

    assert_eq!(true.option(1), Some(1));
    assert_eq!(false.option(1), None);

    assert_eq!(1.tap(|&n| {
        assert_eq!(n, 1);
        2
    }), 1);

    assert_eq!(123.ok().swap(), 123.err());

    assert_eq!(123.once(), (123,));
    assert_eq!(123.twice(), (123, 123));
    assert_eq!(123.thrice(), (123, 123, 123));
}
<|endoftext|>


<commit_before>extern crate gl as gl_lib;

mod context;

pub use gl_lib as gl;
pub use context::Context;
<commit_msg>Fix gl exports in certain circumstances<commit_after>extern crate gl as gl_lib;

mod context;

pub mod gl {
    pub use super::gl_lib::*;
}

pub use context::Context;
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(collections)]
#![feature(std_misc)]
//! Simple [libtecla](http://www.astro.caltech.edu/~mcs/tecla/libtecla.html) wrapper.

extern crate libc;
use libc::{c_char, c_int, size_t};

use std::ffi::{CString, CStr};
use std::string::as_string;
use std::str::from_utf8_unchecked;
use std::ptr;

pub type CplMatchFn = fn(*mut WordCompletion, *mut c_char, *const c_char, c_int) -> c_int;

#[repr(C)]
pub struct GetLine;
#[repr(C)]
pub struct ExpandFile;
/*pub struct FileExpansion {
    exists: c_int,
    nfile: c_int,
    files: *mut char,
}*/
#[repr(C)]
pub struct WordCompletion;

// will add functions as needed
#[link(name = "tecla")]
extern {
    fn new_GetLine(linelen: size_t, histlen: size_t) -> *mut GetLine;
    fn del_GetLine(gl: *mut GetLine) -> *mut GetLine;
    fn gl_get_line(gl: *mut GetLine,
                   prompt: *const c_char,
                   start_line: *const c_char,
                   start_pos: c_int) -> *const c_char;
    fn gl_query_char(gl: *mut GetLine, prompt: *const c_char, defchar: c_char) -> c_int;
    fn new_ExpandFile() -> *mut ExpandFile;
    fn del_ExpandFile(ef: *mut ExpandFile) -> *mut ExpandFile;
    // fn ef_expand_file(ef: *mut ExpandFile,
    //                  path: *const c_char,
    //                  pathlen: c_int) -> *mut FileExpansion;
    // fn el_list_expansions(result: *mut FileExpansion,
    //                      fp: *mut FILE,
    //                      term_width: c_int) -> c_int;
    // fn ef_last_error(ef: *mut ExpandFile) -> *const c_char;
    fn new_WordCompletion() -> *mut WordCompletion;
    fn del_WordCompletion(cpl: *mut WordCompletion) -> WordCompletion;
    /*fn gl_completion_action(gl: *mut GetLine,
                            data: *const void,
                            match_fn: CplMatchFn,
                            list_only: c_int,
                            name: *const c_char,
                            keyseq: *const c_char) -> c_int;*/
    fn gl_customize_completion(gl: *mut GetLine,
                               data: *const c_char,
                               match_fn: &CplMatchFn) -> c_int;
    fn gl_save_history(gl: *mut GetLine,
                       filename: *const c_char,
                       comment: *const c_char,
                       max_lines: c_int);
    fn gl_load_history(gl: *mut GetLine,
                       filename: *const c_char,
                       comment: *const c_char);
    fn gl_ignore_signal(gl: *mut GetLine, signo: c_int);
    fn gl_erase_terminal(gl: *mut GetLine) -> c_int;
    fn cpl_file_completions(cpl: *mut WordCompletion,
                            data: *const c_char,
                            line: *const c_char,
                            word_end: c_int) -> c_int;
}

///Creates new GetLine object
pub fn new_gl(linelen: u64, histlen: u64) -> *mut GetLine {
    let mut res: *mut GetLine;
    unsafe {
        res = new_GetLine(linelen, histlen);
    }
    res
}

///Deletes GetLine object
pub fn del_gl(gl: *mut GetLine) -> *mut GetLine {
    unsafe {
        del_GetLine(gl)
    }
}

///Creates new WordCompletion object
pub fn new_wc() -> *mut WordCompletion {
    unsafe {
        new_WordCompletion()
    }
}

///Deletes WordCompletion object
pub fn del_wc(cpl: *mut WordCompletion) -> WordCompletion {
    unsafe {
        del_WordCompletion(cpl)
    }
}

///Creates new ExpandFile object
pub fn new_ef() -> *mut ExpandFile {
    unsafe {
        new_ExpandFile()
    }
}

///Deletes ExpandFile object
pub fn del_ef(ef: *mut ExpandFile) -> *mut ExpandFile {
    unsafe {
        del_ExpandFile(ef)
    }
}

///Gets line from user using GetLine object
pub fn get_line(gl: *mut GetLine, prompt: &str) -> String {
    let c_prompt = CString::new(prompt.as_bytes()).unwrap();
    let start: *const i8 = ptr::null();
    let mut res: &str;
    unsafe {
        let out = CStr::from_ptr(gl_get_line(gl, c_prompt.as_ptr(), start, -1));
        res = from_utf8_unchecked(out.to_bytes());
    }
    as_string(res).clone()
}

///Returns the character read, or 0 if unreadable
pub fn query_char(gl: *mut GetLine, prompt: &str, defchar: char) -> char {
    let c_prompt = CString::new(prompt.as_bytes()).unwrap();
    let mut res: u8;
    unsafe {
        let out = gl_query_char(gl, c_prompt.as_ptr(), defchar as c_char);
        if out > 0 {
            res = out as u8;
        } else {
            res = 0;
        }
    }
    res as char
}

///Saves history to a file
pub fn save_history(gl: *mut GetLine, file: &str, comment: &str, max: usize) {
    let c_file = CString::new(file.as_bytes()).unwrap();
    let c_comment = CString::new(comment.as_bytes()).unwrap();
    let c_max = max as c_int;
    unsafe {
        gl_save_history(gl, c_file.as_ptr(), c_comment.as_ptr(), c_max)
    }
}

///Loads history from a file
pub fn load_history(gl: *mut GetLine, file: &str, comment: &str) {
    let c_file = CString::new(file.as_bytes()).unwrap();
    let c_comment = CString::new(comment.as_bytes()).unwrap();
    unsafe {
        gl_load_history(gl, c_file.as_ptr(), c_comment.as_ptr())
    }
}

///Ignore specified signal
pub fn ignore(gl: *mut GetLine, sig: isize) {
    unsafe {
        gl_ignore_signal(gl, sig as c_int)
    }
}

///Clear screen
pub fn clear(gl: *mut GetLine) -> i32 {
    unsafe {
        gl_erase_terminal(gl)
    }
}

///Sets the completion function
pub fn custom_complete(gl: *mut GetLine, data: &mut str, func: CplMatchFn) -> i32 {
    let c_data = CString::new(data.as_bytes()).unwrap();
    unsafe {
        gl_customize_completion(gl, c_data.as_ptr(), &func)
    }
}

///Calls built-in libtecla file completion function
pub fn builtin_complete(cpl: *mut WordCompletion, data: &mut str, line: &str, word_end: i32) -> i32 {
    let c_line = CString::new(line.as_bytes()).unwrap();
    let c_data = CString::new(data.as_bytes()).unwrap();
    unsafe {
        cpl_file_completions(cpl, c_data.as_ptr(), c_line.as_ptr(), word_end)
    }
}
/*#[test]
fn it_works() {
}*/
<commit_msg>added cpl_add_completion<commit_after>#![feature(libc)]
#![feature(collections)]
#![feature(std_misc)]
//! Simple [libtecla](http://www.astro.caltech.edu/~mcs/tecla/libtecla.html) wrapper.

extern crate libc;
use libc::{c_char, c_int, size_t};

use std::ffi::{CString, CStr};
use std::string::as_string;
use std::str::from_utf8_unchecked;
use std::ptr;

pub type CplMatchFn = fn(*mut WordCompletion, *mut c_char, *const c_char, c_int) -> c_int;

#[repr(C)]
pub struct GetLine;
#[repr(C)]
pub struct ExpandFile;
/*pub struct FileExpansion {
    exists: c_int,
    nfile: c_int,
    files: *mut char,
}*/
#[repr(C)]
pub struct WordCompletion;

// will add functions as needed
#[link(name = "tecla")]
extern {
    fn new_GetLine(linelen: size_t, histlen: size_t) -> *mut GetLine;
    fn del_GetLine(gl: *mut GetLine) -> *mut GetLine;
    fn gl_get_line(gl: *mut GetLine,
                   prompt: *const c_char,
                   start_line: *const c_char,
                   start_pos: c_int) -> *const c_char;
    fn gl_query_char(gl: *mut GetLine, prompt: *const c_char, defchar: c_char) -> c_int;
    fn new_ExpandFile() -> *mut ExpandFile;
    fn del_ExpandFile(ef: *mut ExpandFile) -> *mut ExpandFile;
    // fn ef_expand_file(ef: *mut ExpandFile,
    //                  path: *const c_char,
    //                  pathlen: c_int) -> *mut FileExpansion;
    // fn el_list_expansions(result: *mut FileExpansion,
    //                      fp: *mut FILE,
    //                      term_width: c_int) -> c_int;
    // fn ef_last_error(ef: *mut ExpandFile) -> *const c_char;
    fn new_WordCompletion() -> *mut WordCompletion;
    fn del_WordCompletion(cpl: *mut WordCompletion) -> WordCompletion;
    /*fn gl_completion_action(gl: *mut GetLine,
                            data: *const void,
                            match_fn: CplMatchFn,
                            list_only: c_int,
                            name: *const c_char,
                            keyseq: *const c_char) -> c_int;*/
    fn gl_customize_completion(gl: *mut GetLine,
                               data: *const c_char,
                               match_fn: &CplMatchFn) -> c_int;
    fn gl_save_history(gl: *mut GetLine,
                       filename: *const c_char,
                       comment: *const c_char,
                       max_lines: c_int);
    fn gl_load_history(gl: *mut GetLine,
                       filename: *const c_char,
                       comment: *const c_char);
    fn gl_ignore_signal(gl: *mut GetLine, signo: c_int);
    fn gl_erase_terminal(gl: *mut GetLine) -> c_int;
    fn cpl_file_completions(cpl: *mut WordCompletion,
                            data: *const c_char,
                            line: *const c_char,
                            word_end: c_int) -> c_int;
    fn cpl_add_completion(cpl: *mut WordCompletion,
                          line: *const c_char,
                          word_start: c_int,
                          word_end: c_int,
                          suffix: *const c_char,
                          type_suffix: *const c_char,
                          cont_suffix: *const c_char) -> c_int;
}

///Creates new GetLine object
pub fn new_gl(linelen: u64, histlen: u64) -> *mut GetLine {
    let mut res: *mut GetLine;
    unsafe {
        res = new_GetLine(linelen, histlen);
    }
    res
}

///Deletes GetLine object
pub fn del_gl(gl: *mut GetLine) -> *mut GetLine {
    unsafe {
        del_GetLine(gl)
    }
}

///Creates new WordCompletion object
pub fn new_wc() -> *mut WordCompletion {
    unsafe {
        new_WordCompletion()
    }
}

///Deletes WordCompletion object
pub fn del_wc(cpl: *mut WordCompletion) -> WordCompletion {
    unsafe {
        del_WordCompletion(cpl)
    }
}

///Creates new ExpandFile object
pub fn new_ef() -> *mut ExpandFile {
    unsafe {
        new_ExpandFile()
    }
}

///Deletes ExpandFile object
pub fn del_ef(ef: *mut ExpandFile) -> *mut ExpandFile {
    unsafe {
        del_ExpandFile(ef)
    }
}

///Gets line from user using GetLine object
pub fn get_line(gl: *mut GetLine, prompt: &str) -> String {
    let c_prompt = CString::new(prompt.as_bytes()).unwrap();
    let start: *const i8 = ptr::null();
    let mut res: &str;
    unsafe {
        let out = CStr::from_ptr(gl_get_line(gl, c_prompt.as_ptr(), start, -1));
        res = from_utf8_unchecked(out.to_bytes());
    }
    as_string(res).clone()
}

///Returns the character read, or 0 if unreadable
pub fn query_char(gl: *mut GetLine, prompt: &str, defchar: char) -> char {
    let c_prompt = CString::new(prompt.as_bytes()).unwrap();
    let mut res: u8;
    unsafe {
        let out = gl_query_char(gl, c_prompt.as_ptr(), defchar as c_char);
        if out > 0 {
            res = out as u8;
        } else {
            res = 0;
        }
    }
    res as char
}

///Saves history to a file
pub fn save_history(gl: *mut GetLine, file: &str, comment: &str, max: usize) {
    let c_file = CString::new(file.as_bytes()).unwrap();
    let c_comment = CString::new(comment.as_bytes()).unwrap();
    let c_max = max as c_int;
    unsafe {
        gl_save_history(gl, c_file.as_ptr(), c_comment.as_ptr(), c_max)
    }
}

///Loads history from a file
pub fn load_history(gl: *mut GetLine, file: &str, comment: &str) {
    let c_file = CString::new(file.as_bytes()).unwrap();
    let c_comment = CString::new(comment.as_bytes()).unwrap();
    unsafe {
        gl_load_history(gl, c_file.as_ptr(), c_comment.as_ptr())
    }
}

///Ignore specified signal
pub fn ignore(gl: *mut GetLine, sig: isize) {
    unsafe {
        gl_ignore_signal(gl, sig as c_int)
    }
}

///Clear screen
pub fn clear(gl: *mut GetLine) -> i32 {
    unsafe {
        gl_erase_terminal(gl)
    }
}

///Sets the completion function
pub fn custom_complete(gl: *mut GetLine, data: &mut str, func: CplMatchFn) -> i32 {
    let c_data = CString::new(data.as_bytes()).unwrap();
    unsafe {
        gl_customize_completion(gl, c_data.as_ptr(), &func)
    }
}

///Calls built-in libtecla file completion function
pub fn builtin_complete(cpl: *mut WordCompletion, data: &mut str, line: &str, word_end: i32) -> i32 {
    let c_line = CString::new(line.as_bytes()).unwrap();
    let c_data = CString::new(data.as_bytes()).unwrap();
    unsafe {
        cpl_file_completions(cpl, c_data.as_ptr(), c_line.as_ptr(), word_end)
    }
}

///Calls cpl_add_completion
pub fn add_completion(wc: *mut WordCompletion,
                      line: *const c_char,
                      word_start: c_int,
                      word_end: c_int,
                      suffix: *const c_char,
                      type_suffix: *const c_char,
                      cont_suffix: *const c_char) -> c_int {
    unsafe {
        cpl_add_completion(wc, line, word_start, word_end, suffix, type_suffix, cont_suffix)
    }
}
<|endoftext|>