<commit_before>//! It can be useful to not have to worry about missing keys in a map.
//! If a key is requested that doesn't have a value a default value is simply returned.
//! This is exactly what this library provides.
//!
//! ## Examples

//! ### Counter
//! A clear use case of this is when counting the unique elements in a list.
//! Here you want to add one to the existing value in the map for that key.
//! This is a problem for the first addition when there's no value for the key yet.
//! With this library you can specify when creating the map that the default value should be zero.
//!

//! ```rust
//! # use defaultmap::*;
//! let nums = [1, 4, 3, 3, 4, 2, 4];
//! let mut counts:  DefaultHashMap<i32, i32> = DefaultHashMap::new(0);
//! // DefaultHashMap::default() is equivalent.
//!
//! for num in nums.into_iter() {
//!     counts[*num] += 1;
//! }
//!
//! println!("{:?}", counts);
//! // DefaultHashMap { map: {1: 1, 3: 2, 2: 1, 4: 3}, default: 0 }
//!
//! # assert_eq!(1, counts[1]);
//! # assert_eq!(1, counts[2]);
//! # assert_eq!(2, counts[3]);
//! # assert_eq!(3, counts[4]);
//! ```
//!

//! ### Synonym lists
//!
//! Another way the default map can be used is using a map filled with other collections, such as a
//! `Vec`, a `HashMap` or even another default map.
//! Next follows some code to create a map where we start with tuples of synonyms and we end with a
//! map that contains the list of synonyms for each word.
//!
//! ```rust
//! # use defaultmap::*;
//!
//! let synonym_tuples = [
//!     ("nice", "sweet"),
//!     ("sweet", "candy"),
//!     ("nice", "entertaining"),
//!     ("nice", "good"),
//!     ("entertaining", "absorbing"),
//! ];
//!
//! let mut synonym_map: DefaultHashMap<&str, Vec<&str>> = DefaultHashMap::new(vec![]);
//! // DefaultHashMap::default() is equivalent.
//!
//! for &(l, r) in synonym_tuples.into_iter() {
//!     synonym_map[l].push(r);
//!     synonym_map[r].push(l);
//! }
//!
//! assert_eq!(synonym_map["good"], vec!["nice"]);
//! assert_eq!(synonym_map["nice"], vec!["sweet", "entertaining", "good"]);
//! assert_eq!(synonym_map["evil"], Vec::<&str>::new());
//! ```
//!

pub use hashmap::DefaultHashMap;

mod hashmap {
    use std::hash::Hash;
    use std::collections::HashMap;
    use std::collections::hash_map::*;
    use std::borrow::Borrow;
    use std::ops::{Index, IndexMut};

    /// A `HashMap` that has returns a default when keys are accessed that are not present.
    #[derive(PartialEq, Eq, Debug)]
    pub struct DefaultHashMap<K: Eq + Hash, V: Clone> {
        map: HashMap<K, V>,
        default: V,
    }

    impl<K: Eq + Hash, V: Default + Clone> Default for DefaultHashMap<K, V> {
        /// The `default()` constructor creates an empty DefaultHashMap with the default of `V`
        /// as the default for missing keys.
        /// This is desired default for most use cases, if your case requires a
        /// different default you should use the `new()` constructor.
        fn default() -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::default(),
                default: V::default(),
            }
        }
    }

    impl<K: Eq + Hash, V: Default + Clone> From<HashMap<K, V>> for DefaultHashMap<K, V> {
        /// If you already have a `HashMap` that you would like to convert to a
        /// `DefaultHashMap` you can use the `into()` method on the `HashMap` or the
        /// `from()` constructor of `DefaultHashMap`.
        /// The default value for missing keys will be `V::default()`,
        /// if this is not desired `DefaultHashMap::new_with_map()` should be used.
        fn from(map: HashMap<K, V>) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: map,
                default: V::default(),
            }
        }
    }

    impl<K: Eq + Hash, V: Clone> Into<HashMap<K, V>> for DefaultHashMap<K, V> {
        /// The into method can be used to convert a `DefaultHashMap` back into a
        /// `HashMap`.
        fn into(self) -> HashMap<K, V> {
            self.map
        }
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        /// Creates an empty `DefaultHashmap` with `default` as the default for missing keys.
        /// When the provided `default` is equivalent to `V::default()` it is preferred to use
        /// `DefaultHashMap::default()` instead.
        pub fn new(default: V) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::new(),
                default: default,
            }
        }

        /// Creates a `DefaultHashMap` based on a default and an already existing `HashMap`.
        /// If `V::default()` is the supplied default, usage of the `from()` constructor or the
        /// `into()` method on the original `HashMap` is preferred.
        pub fn new_with_map(default: V, map: HashMap<K, V>) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: map,
                default: default,
            }
        }

        /// Returns a reference to the value stored for the provided key.
        /// If the key is not in the `DefaultHashMap` a reference to the default value is returned.
        /// Usually the `map[key]` method of retrieving keys is prefered over using `get` directly.
        /// This method accepts both references and owned values as the key.
        pub fn get<Q, QB: Borrow<Q>>(&self, key: QB) -> &V
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.get(key.borrow()).unwrap_or(&self.default)
        }

        /// Returns a mutable reference to the value stored for the provided key.
        /// If there is no value stored for the key the default value is first inserted for this
        /// key before returning the reference.
        /// Usually the `map[key] = new_val` is prefered over using `get_mut` directly.
        /// This method only accepts owned values as the key.
        pub fn get_mut(&mut self, key: K) -> &mut V {
            self.map.entry(key).or_insert(self.default.clone())
        }
    }

    /// Implements the `Index` trait so you can do `map[key]`.
    /// Nonmutable indexing can be done both by passing a reference or an owned value as the key.
    impl<'a, K: Eq + Hash, KB: Borrow<K>, V: Clone> Index<KB> for DefaultHashMap<K, V> {
        type Output = V;

        fn index(&self, index: KB) -> &V {
            self.get(index)
        }
    }

    /// Implements the `IndexMut` trait so you can do `map[key] = val`.
    /// Mutably indexing can only be done when passing an owned value as the key.
    impl<K: Eq + Hash, V: Clone> IndexMut<K> for DefaultHashMap<K, V> {
        #[inline]
        fn index_mut(&mut self, index: K) -> &mut V {
            self.get_mut(index)
        }
    }

    /// These methods simply forward to the underlying `HashMap`, see that
    /// [documentation](https://doc.rust-lang.org/std/collections/struct.HashMap.html) for
    /// the usage of these methods.
    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        pub fn capacity(&self) -> usize {
            self.map.capacity()
        }
        #[inline]
        pub fn reserve(&mut self, additional: usize) {
            self.map.reserve(additional)
        }
        #[inline]
        pub fn shrink_to_fit(&mut self) {
            self.map.shrink_to_fit()
        }
        #[inline]
        pub fn keys(&self) -> Keys<K, V> {
            self.map.keys()
        }
        #[inline]
        pub fn values(&self) -> Values<K, V> {
            self.map.values()
        }
        #[inline]
        pub fn values_mut(&mut self) -> ValuesMut<K, V> {
            self.map.values_mut()
        }
        #[inline]
        pub fn iter(&self) -> Iter<K, V> {
            self.map.iter()
        }
        #[inline]
        pub fn iter_mut(&mut self) -> IterMut<K, V> {
            self.map.iter_mut()
        }
        #[inline]
        pub fn entry(&mut self, key: K) -> Entry<K, V> {
            self.map.entry(key)
        }
        #[inline]
        pub fn len(&self) -> usize {
            self.map.len()
        }
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.map.is_empty()
        }
        #[inline]
        pub fn drain(&mut self) -> Drain<K, V> {
            self.map.drain()
        }
        #[inline]
        pub fn clear(&mut self) {
            self.map.clear()
        }
        #[inline]
        pub fn insert(&mut self, k: K, v: V) -> Option<V> {
            self.map.insert(k, v)
        }
        #[inline]
        pub fn contains_key<Q>(&self, k: &Q) -> (bool)
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.contains_key(k)
        }
        #[inline]
        pub fn remove<Q>(&mut self, k: &Q) -> (Option<V>)
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.remove(k)
        }
    }

}

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

    #[test]
    fn add() {
        let mut map: DefaultHashMap<i32, i32> = DefaultHashMap::default();
        *map.get_mut(0) += 1;
        map[1] += 4;
        map[2] = map[0] + map.get(&1);
        assert_eq!(*map.get(0), 1);
        assert_eq!(*map.get(&0), 1);
        assert_eq!(map[0], 1);
        assert_eq!(map[&0], 1);
        assert_eq!(*map.get(&1), 4);
        assert_eq!(*map.get(&2), 5);
        assert_eq!(*map.get(999), 0);
        assert_eq!(*map.get(&999), 0);
        assert_eq!(map[999], 0);
        assert_eq!(map[&999], 0);
    }

    #[test]
    fn counter() {
        let nums = [1, 4, 3, 3, 4, 2, 4];
        let mut counts: DefaultHashMap<i32, i32> = DefaultHashMap::default();
        for num in nums.into_iter() {
            counts[*num] += 1;
        }

        assert_eq!(1, counts[1]);
        assert_eq!(1, counts[2]);
        assert_eq!(2, counts[3]);
        assert_eq!(3, counts[4]);
        assert_eq!(0, counts[5]);
    }

    #[test]
    fn synonyms() {
        let synonym_tuples = [("nice", "sweet"),
                              ("sweet", "candy"),
                              ("nice", "entertaining"),
                              ("nice", "good"),
                              ("entertaining", "absorbing")];

        let mut synonym_map: DefaultHashMap<&str, Vec<&str>> = DefaultHashMap::default();

        for &(l, r) in synonym_tuples.into_iter() {
            synonym_map[l].push(r);
            synonym_map[r].push(l);
        }

        println!("{:#?}", synonym_map);
        assert_eq!(synonym_map["good"], vec!["nice"]);
        assert_eq!(synonym_map["nice"], vec!["sweet", "entertaining", "good"]);
        assert_eq!(synonym_map["evil"], Vec::<&str>::new());
        // assert!(false)
    }

    #[derive(Clone)]
    struct Clonable;

    #[derive(Default, Clone)]
    struct DefaultableValue;

    #[derive(Hash, Eq, PartialEq)]
    struct Hashable(i32);

    #[test]
    fn minimal_derives() {
        let minimal: DefaultHashMap<Hashable, Clonable> = DefaultHashMap::new(Clonable);
        let clonable: DefaultHashMap<Hashable, DefaultableValue> = DefaultHashMap::default();
    }

}
<commit_msg>Tests: Add a test for the From and Into implementations<commit_after>//! It can be useful to not have to worry about missing keys in a map.
//! If a key is requested that doesn't have a value a default value is simply returned.
//! This is exactly what this library provides.
//!
//! ## Examples

//! ### Counter
//! A clear use case of this is when counting the unique elements in a list.
//! Here you want to add one to the existing value in the map for that key.
//! This is a problem for the first addition when there's no value for the key yet.
//! With this library you can specify when creating the map that the default value should be zero.
//!

//! ```rust
//! # use defaultmap::*;
//! let nums = [1, 4, 3, 3, 4, 2, 4];
//! let mut counts:  DefaultHashMap<i32, i32> = DefaultHashMap::new(0);
//! // DefaultHashMap::default() is equivalent.
//!
//! for num in nums.into_iter() {
//!     counts[*num] += 1;
//! }
//!
//! println!("{:?}", counts);
//! // DefaultHashMap { map: {1: 1, 3: 2, 2: 1, 4: 3}, default: 0 }
//!
//! # assert_eq!(1, counts[1]);
//! # assert_eq!(1, counts[2]);
//! # assert_eq!(2, counts[3]);
//! # assert_eq!(3, counts[4]);
//! ```
//!

//! ### Synonym lists
//!
//! Another way the default map can be used is using a map filled with other collections, such as a
//! `Vec`, a `HashMap` or even another default map.
//! Next follows some code to create a map where we start with tuples of synonyms and we end with a
//! map that contains the list of synonyms for each word.
//!
//! ```rust
//! # use defaultmap::*;
//!
//! let synonym_tuples = [
//!     ("nice", "sweet"),
//!     ("sweet", "candy"),
//!     ("nice", "entertaining"),
//!     ("nice", "good"),
//!     ("entertaining", "absorbing"),
//! ];
//!
//! let mut synonym_map: DefaultHashMap<&str, Vec<&str>> = DefaultHashMap::new(vec![]);
//! // DefaultHashMap::default() is equivalent.
//!
//! for &(l, r) in synonym_tuples.into_iter() {
//!     synonym_map[l].push(r);
//!     synonym_map[r].push(l);
//! }
//!
//! assert_eq!(synonym_map["good"], vec!["nice"]);
//! assert_eq!(synonym_map["nice"], vec!["sweet", "entertaining", "good"]);
//! assert_eq!(synonym_map["evil"], Vec::<&str>::new());
//! ```
//!

pub use hashmap::DefaultHashMap;

mod hashmap {
    use std::hash::Hash;
    use std::collections::HashMap;
    use std::collections::hash_map::*;
    use std::borrow::Borrow;
    use std::ops::{Index, IndexMut};

    /// A `HashMap` that has returns a default when keys are accessed that are not present.
    #[derive(PartialEq, Eq, Debug)]
    pub struct DefaultHashMap<K: Eq + Hash, V: Clone> {
        map: HashMap<K, V>,
        default: V,
    }

    impl<K: Eq + Hash, V: Default + Clone> Default for DefaultHashMap<K, V> {
        /// The `default()` constructor creates an empty DefaultHashMap with the default of `V`
        /// as the default for missing keys.
        /// This is desired default for most use cases, if your case requires a
        /// different default you should use the `new()` constructor.
        fn default() -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::default(),
                default: V::default(),
            }
        }
    }

    impl<K: Eq + Hash, V: Default + Clone> From<HashMap<K, V>> for DefaultHashMap<K, V> {
        /// If you already have a `HashMap` that you would like to convert to a
        /// `DefaultHashMap` you can use the `into()` method on the `HashMap` or the
        /// `from()` constructor of `DefaultHashMap`.
        /// The default value for missing keys will be `V::default()`,
        /// if this is not desired `DefaultHashMap::new_with_map()` should be used.
        fn from(map: HashMap<K, V>) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: map,
                default: V::default(),
            }
        }
    }

    impl<K: Eq + Hash, V: Clone> Into<HashMap<K, V>> for DefaultHashMap<K, V> {
        /// The into method can be used to convert a `DefaultHashMap` back into a
        /// `HashMap`.
        fn into(self) -> HashMap<K, V> {
            self.map
        }
    }

    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        /// Creates an empty `DefaultHashmap` with `default` as the default for missing keys.
        /// When the provided `default` is equivalent to `V::default()` it is preferred to use
        /// `DefaultHashMap::default()` instead.
        pub fn new(default: V) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: HashMap::new(),
                default: default,
            }
        }

        /// Creates a `DefaultHashMap` based on a default and an already existing `HashMap`.
        /// If `V::default()` is the supplied default, usage of the `from()` constructor or the
        /// `into()` method on the original `HashMap` is preferred.
        pub fn new_with_map(default: V, map: HashMap<K, V>) -> DefaultHashMap<K, V> {
            DefaultHashMap {
                map: map,
                default: default,
            }
        }

        /// Returns a reference to the value stored for the provided key.
        /// If the key is not in the `DefaultHashMap` a reference to the default value is returned.
        /// Usually the `map[key]` method of retrieving keys is prefered over using `get` directly.
        /// This method accepts both references and owned values as the key.
        pub fn get<Q, QB: Borrow<Q>>(&self, key: QB) -> &V
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.get(key.borrow()).unwrap_or(&self.default)
        }

        /// Returns a mutable reference to the value stored for the provided key.
        /// If there is no value stored for the key the default value is first inserted for this
        /// key before returning the reference.
        /// Usually the `map[key] = new_val` is prefered over using `get_mut` directly.
        /// This method only accepts owned values as the key.
        pub fn get_mut(&mut self, key: K) -> &mut V {
            self.map.entry(key).or_insert(self.default.clone())
        }
    }

    /// Implements the `Index` trait so you can do `map[key]`.
    /// Nonmutable indexing can be done both by passing a reference or an owned value as the key.
    impl<'a, K: Eq + Hash, KB: Borrow<K>, V: Clone> Index<KB> for DefaultHashMap<K, V> {
        type Output = V;

        fn index(&self, index: KB) -> &V {
            self.get(index)
        }
    }

    /// Implements the `IndexMut` trait so you can do `map[key] = val`.
    /// Mutably indexing can only be done when passing an owned value as the key.
    impl<K: Eq + Hash, V: Clone> IndexMut<K> for DefaultHashMap<K, V> {
        #[inline]
        fn index_mut(&mut self, index: K) -> &mut V {
            self.get_mut(index)
        }
    }

    /// These methods simply forward to the underlying `HashMap`, see that
    /// [documentation](https://doc.rust-lang.org/std/collections/struct.HashMap.html) for
    /// the usage of these methods.
    impl<K: Eq + Hash, V: Clone> DefaultHashMap<K, V> {
        pub fn capacity(&self) -> usize {
            self.map.capacity()
        }
        #[inline]
        pub fn reserve(&mut self, additional: usize) {
            self.map.reserve(additional)
        }
        #[inline]
        pub fn shrink_to_fit(&mut self) {
            self.map.shrink_to_fit()
        }
        #[inline]
        pub fn keys(&self) -> Keys<K, V> {
            self.map.keys()
        }
        #[inline]
        pub fn values(&self) -> Values<K, V> {
            self.map.values()
        }
        #[inline]
        pub fn values_mut(&mut self) -> ValuesMut<K, V> {
            self.map.values_mut()
        }
        #[inline]
        pub fn iter(&self) -> Iter<K, V> {
            self.map.iter()
        }
        #[inline]
        pub fn iter_mut(&mut self) -> IterMut<K, V> {
            self.map.iter_mut()
        }
        #[inline]
        pub fn entry(&mut self, key: K) -> Entry<K, V> {
            self.map.entry(key)
        }
        #[inline]
        pub fn len(&self) -> usize {
            self.map.len()
        }
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.map.is_empty()
        }
        #[inline]
        pub fn drain(&mut self) -> Drain<K, V> {
            self.map.drain()
        }
        #[inline]
        pub fn clear(&mut self) {
            self.map.clear()
        }
        #[inline]
        pub fn insert(&mut self, k: K, v: V) -> Option<V> {
            self.map.insert(k, v)
        }
        #[inline]
        pub fn contains_key<Q>(&self, k: &Q) -> (bool)
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.contains_key(k)
        }
        #[inline]
        pub fn remove<Q>(&mut self, k: &Q) -> (Option<V>)
            where K: Borrow<Q>,
                  Q: ?Sized + Hash + Eq
        {
            self.map.remove(k)
        }
    }

}

#[cfg(test)]
mod tests {
    use super::DefaultHashMap;
    use std::collections::HashMap;

    #[test]
    fn add() {
        let mut map: DefaultHashMap<i32, i32> = DefaultHashMap::default();
        *map.get_mut(0) += 1;
        map[1] += 4;
        map[2] = map[0] + map.get(&1);
        assert_eq!(*map.get(0), 1);
        assert_eq!(*map.get(&0), 1);
        assert_eq!(map[0], 1);
        assert_eq!(map[&0], 1);
        assert_eq!(*map.get(&1), 4);
        assert_eq!(*map.get(&2), 5);
        assert_eq!(*map.get(999), 0);
        assert_eq!(*map.get(&999), 0);
        assert_eq!(map[999], 0);
        assert_eq!(map[&999], 0);
    }

    #[test]
    fn counter() {
        let nums = [1, 4, 3, 3, 4, 2, 4];
        let mut counts: DefaultHashMap<i32, i32> = DefaultHashMap::default();
        for num in nums.into_iter() {
            counts[*num] += 1;
        }

        assert_eq!(1, counts[1]);
        assert_eq!(1, counts[2]);
        assert_eq!(2, counts[3]);
        assert_eq!(3, counts[4]);
        assert_eq!(0, counts[5]);
    }

    #[test]
    fn synonyms() {
        let synonym_tuples = [("nice", "sweet"),
                              ("sweet", "candy"),
                              ("nice", "entertaining"),
                              ("nice", "good"),
                              ("entertaining", "absorbing")];

        let mut synonym_map: DefaultHashMap<&str, Vec<&str>> = DefaultHashMap::default();

        for &(l, r) in synonym_tuples.into_iter() {
            synonym_map[l].push(r);
            synonym_map[r].push(l);
        }

        println!("{:#?}", synonym_map);
        assert_eq!(synonym_map["good"], vec!["nice"]);
        assert_eq!(synonym_map["nice"], vec!["sweet", "entertaining", "good"]);
        assert_eq!(synonym_map["evil"], Vec::<&str>::new());
        // assert!(false)
    }

    #[derive(Clone)]
    struct Clonable;

    #[derive(Default, Clone)]
    struct DefaultableValue;

    #[derive(Hash, Eq, PartialEq)]
    struct Hashable(i32);

    #[test]
    fn minimal_derives() {
        let _: DefaultHashMap<Hashable, Clonable> = DefaultHashMap::new(Clonable);
        let _: DefaultHashMap<Hashable, DefaultableValue> = DefaultHashMap::default();
    }

    #[test]
    fn from() {
        let normal: HashMap<i32, i32> = vec![(0, 1), (2, 3)].into_iter().collect();
        let mut default: DefaultHashMap<_, _> = normal.into();
        default.get_mut(4);
        assert_eq!(default[0], 1);
        assert_eq!(default[2], 3);
        assert_eq!(default[1], 0);
        assert_eq!(default[4], 0);
        let expected: HashMap<i32, i32> = vec![(0, 1), (2, 3), (4, 0)].into_iter().collect();
        assert_eq!(expected, default.into());
    }

}
<|endoftext|>


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

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/term) and can be
//! used by adding `term` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//!
//! term = "0.2"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate term;
//! ```
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     write!(t, "hello, ").unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     writeln!(t, "world!").unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(rust_build, feature(staged_api))]
#![cfg_attr(rust_build, staged_api)]
#![cfg_attr(rust_build,
            unstable(feature = "rustc_private",
                     reason = "use the crates.io `term` library instead"))]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stdout terminals.
pub type StdoutTerminal = Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = Terminal<Output = Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout())
        .map(|t| Box::new(t) as Box<StdoutTerminal>)
        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr())
        .map(|t| Box::new(t) as Box<StderrTerminal>)
        .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
}

/// Terminal color definitions
#[allow(missing_docs)]
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK: Color = 0;
    pub const RED: Color = 1;
    pub const GREEN: Color = 2;
    pub const YELLOW: Color = 3;
    pub const BLUE: Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN: Color = 6;
    pub const WHITE: Color = 7;

    pub const BRIGHT_BLACK: Color = 8;
    pub const BRIGHT_RED: Color = 9;
    pub const BRIGHT_GREEN: Color = 10;
    pub const BRIGHT_YELLOW: Color = 11;
    pub const BRIGHT_BLUE: Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN: Color = 14;
    pub const BRIGHT_WHITE: Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color),
}

/// An error arising from interacting with the terminal.
#[derive(Debug)]
pub enum Error {
    /// Indicates an error from any underlying IO
    Io(io::Error),
    /// Indicates an error during terminfo parsing
    TerminfoParsing(terminfo::Error),
    /// Indicates an error expanding a parameterized string from the terminfo database
    ParameterizedExpansion(terminfo::parm::Error),
    /// Indicates that the terminal does not support the requested operation.
    NotSupported,
    /// Indicates that the `TERM` environment variable was unset, and thus we were unable to detect
    /// which terminal we should be using.
    TermUnset,
    /// Indicates that we were unable to find a terminfo entry for the requested terminal.
    TerminfoEntryNotFound,
    /// Indicates that the cursor could not be moved to the requested position.
    CursorDestinationInvalid,
    /// Indicates that the terminal does not support displaying the requested color.
    ///
    /// This is like `NotSupported`, but more specific.
    ColorOutOfRange,
    #[doc(hidden)]
    /// Please don't match against this - if you do, we can't promise we won't break your crate
    /// with a semver-compliant version bump.
    __Nonexhaustive,
}

// manually implemented because std::io::Error does not implement Eq/PartialEq
impl std::cmp::PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        use Error::*;
        match self {
            &Io(_) => false,
            &TerminfoParsing(ref inner1) => {
                match other {
                    &TerminfoParsing(ref inner2) => inner1 == inner2,
                    _ => false,
                }
            }
            &ParameterizedExpansion(ref inner1) => {
                match other {
                    &ParameterizedExpansion(ref inner2) => inner1 == inner2,
                    _ => false,
                }
            }
            &NotSupported => {
                match other {
                    &NotSupported => true,
                    _ => false,
                }
            }
            &TermUnset => {
                match other {
                    &TermUnset => true,
                    _ => false,
                }
            }
            &TerminfoEntryNotFound => {
                match other {
                    &TerminfoEntryNotFound => true,
                    _ => false,
                }
            }
            &CursorDestinationInvalid => {
                match other {
                    &CursorDestinationInvalid => true,
                    _ => false,
                }
            }
            &ColorOutOfRange => {
                match other {
                    &ColorOutOfRange => true,
                    _ => false,
                }
            }
            &__Nonexhaustive => {
                match other {
                    &__Nonexhaustive => true,
                    _ => false,
                }
            }
        }
    }
}

/// The canonical `Result` type using this crate's Error type.
pub type Result<T> = std::result::Result<T, Error>;

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        if let &::Error::Io(ref e) = self {
            write!(f, "{}", e)
        } else {
            f.write_str(self.description())
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use Error::*;
        use std::error::Error;
        match self {
            &Io(ref io) => io.description(),
            &TerminfoParsing(ref e) => e.description(),
            &ParameterizedExpansion(ref e) => e.description(),
            &NotSupported => "operation not supported by the terminal",
            &TermUnset => "TERM environment variable unset, unable to detect a terminal",
            &TerminfoEntryNotFound => "could not find a terminfo entry for this terminal",
            &CursorDestinationInvalid => "could not move cursor to requested position",
            &ColorOutOfRange => "color not supported by the terminal",
            &__Nonexhaustive => "placeholder variant that shouldn't be used",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match self {
            &Error::Io(ref io) => Some(io),
            &Error::TerminfoParsing(ref e) => Some(e),
            &Error::ParameterizedExpansion(ref e) => Some(e),
            _ => None,
        }
    }
}

impl std::convert::From<io::Error> for Error {
    fn from(val: io::Error) -> Self {
        Error::Io(val)
    }
}

impl std::convert::From<terminfo::Error> for Error {
    fn from(val: terminfo::Error) -> Self {
        Error::TerminfoParsing(val)
    }
}

impl std::convert::From<terminfo::parm::Error> for Error {
    fn from(val: terminfo::parm::Error) -> Self {
        Error::ParameterizedExpansion(val)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(())` if the color change code was sent to the terminal, or `Err(e)` if there
    /// was an error.
    fn fg(&mut self, color: color::Color) -> Result<()>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(())` if the color change code was sent to the terminal, or `Err(e)` if there
    /// was an error.
    fn bg(&mut self, color: color::Color) -> Result<()>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(())` if the attribute is
    /// supported and was sent to the terminal, or `Err(e)` if there was an error or the attribute
    /// wasn't supported.
    fn attr(&mut self, attr: Attr) -> Result<()>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and colors to their defaults.
    ///
    /// Returns `Ok(())` if the reset code was printed, or `Err(e)` if there was an error.
    ///
    /// *Note: This does not flush.*
    ///
    /// That means the reset command may get buffered so, if you aren't planning on doing anything
    /// else that might flush stdout's buffer (e.g. writing a line of text), you should flush after
    /// calling reset.
    fn reset(&mut self) -> Result<()>;

    /// Moves the cursor up one line.
    ///
    /// Returns `Ok(())` if the cursor movement code was printed, or `Err(e)` if there was an
    /// error.
    fn cursor_up(&mut self) -> Result<()>;

    /// Deletes the text from the cursor location to the end of the line.
    ///
    /// Returns `Ok(())` if the deletion code was printed, or `Err(e)` if there was an error.
    fn delete_line(&mut self) -> Result<()>;

    /// Moves the cursor to the left edge of the current line.
    ///
    /// Returns `Ok(true)` if the deletion code was printed, or `Err(e)` if there was an error.
    fn carriage_return(&mut self) -> Result<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output;

    /// Returns the contained stream, destroying the `Terminal`
    fn into_inner(self) -> Self::Output where Self: Sized;
}
<commit_msg>Fixup crate attributes<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/term) and can be
//! used by adding `term` to the dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//!
//! term = "0.2"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate term;
//! ```
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     write!(t, "hello, ").unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     writeln!(t, "world!").unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://stebalien.github.io/doc/term/term/",
       test(attr(deny(warnings))))]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stdout terminals.
pub type StdoutTerminal = Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = Terminal<Output = Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout())
        .map(|t| Box::new(t) as Box<StdoutTerminal>)
        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr())
        .map(|t| Box::new(t) as Box<StderrTerminal>)
        .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
}

/// Terminal color definitions
#[allow(missing_docs)]
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK: Color = 0;
    pub const RED: Color = 1;
    pub const GREEN: Color = 2;
    pub const YELLOW: Color = 3;
    pub const BLUE: Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN: Color = 6;
    pub const WHITE: Color = 7;

    pub const BRIGHT_BLACK: Color = 8;
    pub const BRIGHT_RED: Color = 9;
    pub const BRIGHT_GREEN: Color = 10;
    pub const BRIGHT_YELLOW: Color = 11;
    pub const BRIGHT_BLUE: Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN: Color = 14;
    pub const BRIGHT_WHITE: Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color),
}

/// An error arising from interacting with the terminal.
#[derive(Debug)]
pub enum Error {
    /// Indicates an error from any underlying IO
    Io(io::Error),
    /// Indicates an error during terminfo parsing
    TerminfoParsing(terminfo::Error),
    /// Indicates an error expanding a parameterized string from the terminfo database
    ParameterizedExpansion(terminfo::parm::Error),
    /// Indicates that the terminal does not support the requested operation.
    NotSupported,
    /// Indicates that the `TERM` environment variable was unset, and thus we were unable to detect
    /// which terminal we should be using.
    TermUnset,
    /// Indicates that we were unable to find a terminfo entry for the requested terminal.
    TerminfoEntryNotFound,
    /// Indicates that the cursor could not be moved to the requested position.
    CursorDestinationInvalid,
    /// Indicates that the terminal does not support displaying the requested color.
    ///
    /// This is like `NotSupported`, but more specific.
    ColorOutOfRange,
    #[doc(hidden)]
    /// Please don't match against this - if you do, we can't promise we won't break your crate
    /// with a semver-compliant version bump.
    __Nonexhaustive,
}

// manually implemented because std::io::Error does not implement Eq/PartialEq
impl std::cmp::PartialEq for Error {
    fn eq(&self, other: &Error) -> bool {
        use Error::*;
        match self {
            &Io(_) => false,
            &TerminfoParsing(ref inner1) => {
                match other {
                    &TerminfoParsing(ref inner2) => inner1 == inner2,
                    _ => false,
                }
            }
            &ParameterizedExpansion(ref inner1) => {
                match other {
                    &ParameterizedExpansion(ref inner2) => inner1 == inner2,
                    _ => false,
                }
            }
            &NotSupported => {
                match other {
                    &NotSupported => true,
                    _ => false,
                }
            }
            &TermUnset => {
                match other {
                    &TermUnset => true,
                    _ => false,
                }
            }
            &TerminfoEntryNotFound => {
                match other {
                    &TerminfoEntryNotFound => true,
                    _ => false,
                }
            }
            &CursorDestinationInvalid => {
                match other {
                    &CursorDestinationInvalid => true,
                    _ => false,
                }
            }
            &ColorOutOfRange => {
                match other {
                    &ColorOutOfRange => true,
                    _ => false,
                }
            }
            &__Nonexhaustive => {
                match other {
                    &__Nonexhaustive => true,
                    _ => false,
                }
            }
        }
    }
}

/// The canonical `Result` type using this crate's Error type.
pub type Result<T> = std::result::Result<T, Error>;

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        if let &::Error::Io(ref e) = self {
            write!(f, "{}", e)
        } else {
            f.write_str(self.description())
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use Error::*;
        use std::error::Error;
        match self {
            &Io(ref io) => io.description(),
            &TerminfoParsing(ref e) => e.description(),
            &ParameterizedExpansion(ref e) => e.description(),
            &NotSupported => "operation not supported by the terminal",
            &TermUnset => "TERM environment variable unset, unable to detect a terminal",
            &TerminfoEntryNotFound => "could not find a terminfo entry for this terminal",
            &CursorDestinationInvalid => "could not move cursor to requested position",
            &ColorOutOfRange => "color not supported by the terminal",
            &__Nonexhaustive => "placeholder variant that shouldn't be used",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match self {
            &Error::Io(ref io) => Some(io),
            &Error::TerminfoParsing(ref e) => Some(e),
            &Error::ParameterizedExpansion(ref e) => Some(e),
            _ => None,
        }
    }
}

impl std::convert::From<io::Error> for Error {
    fn from(val: io::Error) -> Self {
        Error::Io(val)
    }
}

impl std::convert::From<terminfo::Error> for Error {
    fn from(val: terminfo::Error) -> Self {
        Error::TerminfoParsing(val)
    }
}

impl std::convert::From<terminfo::parm::Error> for Error {
    fn from(val: terminfo::parm::Error) -> Self {
        Error::ParameterizedExpansion(val)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(())` if the color change code was sent to the terminal, or `Err(e)` if there
    /// was an error.
    fn fg(&mut self, color: color::Color) -> Result<()>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(())` if the color change code was sent to the terminal, or `Err(e)` if there
    /// was an error.
    fn bg(&mut self, color: color::Color) -> Result<()>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(())` if the attribute is
    /// supported and was sent to the terminal, or `Err(e)` if there was an error or the attribute
    /// wasn't supported.
    fn attr(&mut self, attr: Attr) -> Result<()>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and colors to their defaults.
    ///
    /// Returns `Ok(())` if the reset code was printed, or `Err(e)` if there was an error.
    ///
    /// *Note: This does not flush.*
    ///
    /// That means the reset command may get buffered so, if you aren't planning on doing anything
    /// else that might flush stdout's buffer (e.g. writing a line of text), you should flush after
    /// calling reset.
    fn reset(&mut self) -> Result<()>;

    /// Moves the cursor up one line.
    ///
    /// Returns `Ok(())` if the cursor movement code was printed, or `Err(e)` if there was an
    /// error.
    fn cursor_up(&mut self) -> Result<()>;

    /// Deletes the text from the cursor location to the end of the line.
    ///
    /// Returns `Ok(())` if the deletion code was printed, or `Err(e)` if there was an error.
    fn delete_line(&mut self) -> Result<()>;

    /// Moves the cursor to the left edge of the current line.
    ///
    /// Returns `Ok(true)` if the deletion code was printed, or `Err(e)` if there was an error.
    fn carriage_return(&mut self) -> Result<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output;

    /// Returns the contained stream, destroying the `Terminal`
    fn into_inner(self) -> Self::Output where Self: Sized;
}
<|endoftext|>


<commit_before>extern crate image;
extern crate rand;
extern crate rayon;
extern crate pbr;

use image::{Rgba, RgbaImage, Pixel};

use pbr::ProgressBar;

use rand::Rng;

use rayon::prelude::*;

#[derive(Clone, Copy, Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn cross_product(&self, b: Point) -> i32 {
        self.x * b.y - self.y * b.x
    }
}

#[derive(Debug, Copy, Clone)]
struct BoundingBox {
    top_left: Point,
    bottom_right: Point,
}

trait Primitive {
    fn is_inside_primitive(&self, p: Point) -> bool;
    fn bounding_box(&self) -> BoundingBox;
    fn get_color(&self) -> Option<Rgba<u8>>;
    fn set_color(&mut self, color: Rgba<u8>);
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,

    span_div: Option<f32>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
            span_div: None,
        }
    }

    fn span_div_save(&mut self) {
        self.span_div = Some(self.span_div());
    }

    fn span_div(&self) -> f32 {
        match self.span_div {
            Some(div) => div,
            None => {
                let span_a = Point {
                    x: self.b.x - self.a.x,
                    y: self.b.y - self.a.y,
                };
                let span_b = Point {
                    x: self.c.x - self.a.x,
                    y: self.c.y - self.a.y,
                };

                1.0 / span_a.cross_product(span_b) as f32
            }
        }
    }
}

impl Primitive for Triangle {
    fn is_inside_primitive(&self, p: Point) -> bool {
        let span_a = Point {
            x: self.b.x - self.a.x,
            y: self.b.y - self.a.y,
        };
        let span_b = Point {
            x: self.c.x - self.a.x,
            y: self.c.y - self.a.y,
        };

        let q = Point {
            x: p.x - self.a.x,
            y: p.y - self.a.y,
        };

        let s = q.cross_product(span_b) as f32 * self.span_div();
        let t = span_a.cross_product(q) as f32 * self.span_div();

        (s >= 0.0) && (t >= 0.0) && ((s + t) <= 1.0)
    }

    fn bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            },
        }
    }

    fn get_color(&self) -> Option<Rgba<u8>> {
        self.color
    }

    fn set_color(&mut self, color: Rgba<u8>) {
        self.color = Some(color);
    }
}

trait PointGenerator {
    fn next_point(&mut self, width: u32, height: u32) -> Point;
}

pub struct RandomPointGenerator {
    rng: Box<Rng>,
}

impl RandomPointGenerator {
    pub fn new() -> RandomPointGenerator {
        RandomPointGenerator { rng: Box::new(rand::weak_rng()) }
    }
}

impl PointGenerator for RandomPointGenerator {
    fn next_point(&mut self, width: u32, height: u32) -> Point {
        Point {
            x: self.rng.gen_range(0, width as i32),
            y: self.rng.gen_range(0, height as i32),
        }
    }
}

pub struct Geometrify {
    point_gen: Box<RandomPointGenerator>,
    iterations: u32,
    samples: u32,
}

impl Geometrify {
    pub fn new(point_gen: Box<RandomPointGenerator>, iterations: u32, samples: u32) -> Geometrify {
        Geometrify {
            point_gen: point_gen,
            iterations: iterations,
            samples: samples,
        }
    }

    pub fn set_iterations(&mut self, iterations: u32) {
        self.iterations = iterations
    }

    pub fn set_samples(&mut self, samples: u32) {
        self.samples = samples
    }

    fn calculate_color(image: &RgbaImage, primitive: &Primitive) -> Rgba<u8> {
        let bb = primitive.bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels(
                (cr / count) as u8,
                (cg / count) as u8,
                (cb / count) as u8,
                (ca / count) as u8,
            )
        }
    }

    fn generate_primitive(&mut self, width: u32, height: u32) -> Triangle {
        Triangle::new(
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
        )
    }

    fn add_to_image(image: &mut RgbaImage, primitive: &Primitive) {
        let bb = primitive.bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let p = Point {
                    x: x as i32,
                    y: y as i32,
                };
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) =
                        Geometrify::mix_color(
                            primitive.get_color().expect("color of triangle not set"),
                            *image.get_pixel(x as u32, y as u32),
                        );
                }
            }
        }
    }

    fn mix_color(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            ((((r1 as u32 + r2 as u32)) / 2) as u8),
            ((((g1 as u32 + g2 as u32)) / 2) as u8),
            ((((b1 as u32 + b2 as u32)) / 2) as u8),
            ((((a1 as u32 + a2 as u32)) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> u32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0i32;

        d += i32::abs((r1 as i32 - r2 as i32));
        d += i32::abs((g1 as i32 - g2 as i32));
        d += i32::abs((b1 as i32 - b2 as i32));
        d += i32::abs((a1 as i32 - a2 as i32));

        d as u32
    }

    fn calculate_difference(original: &RgbaImage,
                            current: &RgbaImage,
                            diff_lut: &Vec<u64>,
                            primitive: &Primitive)
                            -> u64 {
        let bb = primitive.bounding_box();

        // Use LUT to calculate difference outside of the BB
        // TODO: Check whether indices are correct!
        let mut d = diff_lut[diff_lut.len() - 1];
        if bb.bottom_right.y > 0 && bb.bottom_right.x > 0 {
            d -= diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.bottom_right.x > 0 {
            d += diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.bottom_right.y > 0 && bb.top_left.x > 0 {
            d += diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.top_left.x > 0 {
            d -= diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let original_rgb = original.get_pixel(x as u32, y as u32);
                let result_rgb = if (bb.top_left.x as u32 <= x as u32) &&
                                    (x as u32 <= bb.bottom_right.x as u32) &&
                                    (bb.top_left.y as u32 <= y as u32) &&
                                    (y as u32 <= bb.bottom_right.y as u32) &&
                                    (primitive.is_inside_primitive(
                    Point {
                        x: x as i32,
                        y: y as i32,
                    }
                )) {
                    Geometrify::mix_color(
                        *current.get_pixel(x as u32, y as u32),
                        primitive.get_color().expect("triangle color not "),
                    )
                } else {
                    *current.get_pixel(x as u32, y as u32)
                };

                d += Geometrify::difference(*original_rgb, result_rgb) as u64;
            }
        }

        d
    }

    fn calculate_difference_lut(a: &RgbaImage, b: &RgbaImage) -> Vec<u64> {
        let mut result = Vec::new();

        for y in 0..a.height() {
            for x in 0..a.width() {
                let mut ldiff = Geometrify::difference(*a.get_pixel(x, y), *b.get_pixel(x, y)) as
                                u64;
                if x > 0 {
                    ldiff += result[(y * a.width() + x - 1) as usize];
                }
                if y > 0 {
                    ldiff += result[((y - 1) * a.width() + x) as usize];
                }
                if x > 0 && y > 0 {
                    ldiff -= result[((y - 1) * a.width() + x - 1) as usize];
                }

                result.push(ldiff);
            }
        }

        result
    }

    pub fn apply(&mut self, image: RgbaImage) -> RgbaImage {
        let mut progress = ProgressBar::new(self.iterations as u64);
        progress.format("|#--|");

        let mut destination = RgbaImage::new(image.width(), image.height());

        for _ in 0..self.iterations {
            let difference_lut = Geometrify::calculate_difference_lut(&image, &destination);

            let primitives = (0..self.samples)
                .map(|_| self.generate_primitive(image.width(), image.height()))
                .map(
                    |mut p| {
                        p.span_div_save();
                        p
                    }
                )
                .collect::<Vec<Triangle>>();
            let min_primitive = primitives
                .par_iter()
                .map(
                    |primitive| {
                        let mut prim = *primitive;
                        prim.color = Some(Geometrify::calculate_color(&image, &prim));
                        (prim,
                         Geometrify::calculate_difference(
                            &image,
                            &destination,
                            &difference_lut,
                            &prim,
                        ))
                    }
                )
                .min_by_key(|tup| tup.1);

            Geometrify::add_to_image(
                &mut destination,
                &min_primitive.expect("no fitting triangle found").0,
            );
            progress.inc();
        }
        progress.finish_print("done");

        destination
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Use generic PointGenerator in Geometrify.<commit_after>extern crate image;
extern crate rand;
extern crate rayon;
extern crate pbr;

use image::{Rgba, RgbaImage, Pixel};

use pbr::ProgressBar;

use rand::Rng;

use rayon::prelude::*;

#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: i32,
    y: i32,
}

impl Point {
    pub fn cross_product(&self, b: Point) -> i32 {
        self.x * b.y - self.y * b.x
    }
}

#[derive(Debug, Copy, Clone)]
struct BoundingBox {
    top_left: Point,
    bottom_right: Point,
}

trait Primitive {
    fn is_inside_primitive(&self, p: Point) -> bool;
    fn bounding_box(&self) -> BoundingBox;
    fn get_color(&self) -> Option<Rgba<u8>>;
    fn set_color(&mut self, color: Rgba<u8>);
}

#[derive(Debug, Copy, Clone)]
struct Triangle {
    a: Point,
    b: Point,
    c: Point,
    color: Option<Rgba<u8>>,

    span_div: Option<f32>,
}

impl Triangle {
    fn new(a: Point, b: Point, c: Point) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            color: None,
            span_div: None,
        }
    }

    fn span_div_save(&mut self) {
        self.span_div = Some(self.span_div());
    }

    fn span_div(&self) -> f32 {
        match self.span_div {
            Some(div) => div,
            None => {
                let span_a = Point {
                    x: self.b.x - self.a.x,
                    y: self.b.y - self.a.y,
                };
                let span_b = Point {
                    x: self.c.x - self.a.x,
                    y: self.c.y - self.a.y,
                };

                1.0 / span_a.cross_product(span_b) as f32
            }
        }
    }
}

impl Primitive for Triangle {
    fn is_inside_primitive(&self, p: Point) -> bool {
        let span_a = Point {
            x: self.b.x - self.a.x,
            y: self.b.y - self.a.y,
        };
        let span_b = Point {
            x: self.c.x - self.a.x,
            y: self.c.y - self.a.y,
        };

        let q = Point {
            x: p.x - self.a.x,
            y: p.y - self.a.y,
        };

        let s = q.cross_product(span_b) as f32 * self.span_div();
        let t = span_a.cross_product(q) as f32 * self.span_div();

        (s >= 0.0) && (t >= 0.0) && ((s + t) <= 1.0)
    }

    fn bounding_box(&self) -> BoundingBox {
        use std::cmp::{min, max};
        BoundingBox {
            top_left: Point {
                x: min(min(self.a.x, self.b.x), self.c.x),
                y: min(min(self.a.y, self.b.y), self.c.y),
            },
            bottom_right: Point {
                x: max(max(self.a.x, self.b.x), self.c.x),
                y: max(max(self.a.y, self.b.y), self.c.y),
            },
        }
    }

    fn get_color(&self) -> Option<Rgba<u8>> {
        self.color
    }

    fn set_color(&mut self, color: Rgba<u8>) {
        self.color = Some(color);
    }
}

pub trait PointGenerator {
    fn next_point(&mut self, width: u32, height: u32) -> Point;
}

pub struct RandomPointGenerator {
    rng: Box<Rng>,
}

impl RandomPointGenerator {
    pub fn new() -> RandomPointGenerator {
        RandomPointGenerator { rng: Box::new(rand::weak_rng()) }
    }
}

impl PointGenerator for RandomPointGenerator {
    fn next_point(&mut self, width: u32, height: u32) -> Point {
        Point {
            x: self.rng.gen_range(0, width as i32),
            y: self.rng.gen_range(0, height as i32),
        }
    }
}

pub struct Geometrify {
    point_gen: Box<PointGenerator>,
    iterations: u32,
    samples: u32,
}

impl Geometrify {
    pub fn new(point_gen: Box<PointGenerator>, iterations: u32, samples: u32) -> Geometrify {
        Geometrify {
            point_gen: point_gen,
            iterations: iterations,
            samples: samples,
        }
    }

    pub fn set_iterations(&mut self, iterations: u32) {
        self.iterations = iterations
    }

    pub fn set_samples(&mut self, samples: u32) {
        self.samples = samples
    }

    fn calculate_color(image: &RgbaImage, primitive: &Primitive) -> Rgba<u8> {
        let bb = primitive.bounding_box();

        let mut count = 0u64;
        let mut cr = 0u64;
        let mut cg = 0u64;
        let mut cb = 0u64;
        let mut ca = 0u64;

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let (r, g, b, a) = image.get_pixel(x as u32, y as u32).channels4();
                cr += r as u64;
                cg += g as u64;
                cb += b as u64;
                ca += a as u64;
                count += 1;
            }
        }

        if count == 0 {
            Rgba::from_channels(255, 255, 255, 255)
        } else {
            Rgba::from_channels(
                (cr / count) as u8,
                (cg / count) as u8,
                (cb / count) as u8,
                (ca / count) as u8,
            )
        }
    }

    fn generate_primitive(&mut self, width: u32, height: u32) -> Triangle {
        Triangle::new(
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
            self.point_gen.next_point(width, height),
        )
    }

    fn add_to_image(image: &mut RgbaImage, primitive: &Primitive) {
        let bb = primitive.bounding_box();

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let p = Point {
                    x: x as i32,
                    y: y as i32,
                };
                if primitive.is_inside_primitive(p) {
                    *image.get_pixel_mut(x as u32, y as u32) =
                        Geometrify::mix_color(
                            primitive.get_color().expect("color of triangle not set"),
                            *image.get_pixel(x as u32, y as u32),
                        );
                }
            }
        }
    }

    fn mix_color(first: Rgba<u8>, second: Rgba<u8>) -> Rgba<u8> {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();

        Rgba::from_channels(
            ((((r1 as u32 + r2 as u32)) / 2) as u8),
            ((((g1 as u32 + g2 as u32)) / 2) as u8),
            ((((b1 as u32 + b2 as u32)) / 2) as u8),
            ((((a1 as u32 + a2 as u32)) / 2) as u8),
        )
    }

    fn difference(first: Rgba<u8>, second: Rgba<u8>) -> u32 {
        let (r1, g1, b1, a1) = first.channels4();
        let (r2, g2, b2, a2) = second.channels4();
        let mut d = 0i32;

        d += i32::abs((r1 as i32 - r2 as i32));
        d += i32::abs((g1 as i32 - g2 as i32));
        d += i32::abs((b1 as i32 - b2 as i32));
        d += i32::abs((a1 as i32 - a2 as i32));

        d as u32
    }

    fn calculate_difference(original: &RgbaImage,
                            current: &RgbaImage,
                            diff_lut: &Vec<u64>,
                            primitive: &Primitive)
                            -> u64 {
        let bb = primitive.bounding_box();

        // Use LUT to calculate difference outside of the BB
        // TODO: Check whether indices are correct!
        let mut d = diff_lut[diff_lut.len() - 1];
        if bb.bottom_right.y > 0 && bb.bottom_right.x > 0 {
            d -= diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.bottom_right.x > 0 {
            d += diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.bottom_right.x as u32 - 1) as usize];
        }
        if bb.bottom_right.y > 0 && bb.top_left.x > 0 {
            d += diff_lut[((bb.bottom_right.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }
        if bb.top_left.y > 0 && bb.top_left.x > 0 {
            d -= diff_lut[((bb.top_left.y - 1) as u32 * current.width() +
             bb.top_left.x as u32 - 1) as usize];
        }

        for y in bb.top_left.y..bb.bottom_right.y {
            for x in bb.top_left.x..bb.bottom_right.x {
                let original_rgb = original.get_pixel(x as u32, y as u32);
                let result_rgb = if (bb.top_left.x as u32 <= x as u32) &&
                                    (x as u32 <= bb.bottom_right.x as u32) &&
                                    (bb.top_left.y as u32 <= y as u32) &&
                                    (y as u32 <= bb.bottom_right.y as u32) &&
                                    (primitive.is_inside_primitive(
                    Point {
                        x: x as i32,
                        y: y as i32,
                    }
                )) {
                    Geometrify::mix_color(
                        *current.get_pixel(x as u32, y as u32),
                        primitive.get_color().expect("triangle color not "),
                    )
                } else {
                    *current.get_pixel(x as u32, y as u32)
                };

                d += Geometrify::difference(*original_rgb, result_rgb) as u64;
            }
        }

        d
    }

    fn calculate_difference_lut(a: &RgbaImage, b: &RgbaImage) -> Vec<u64> {
        let mut result = Vec::new();

        for y in 0..a.height() {
            for x in 0..a.width() {
                let mut ldiff = Geometrify::difference(*a.get_pixel(x, y), *b.get_pixel(x, y)) as
                                u64;
                if x > 0 {
                    ldiff += result[(y * a.width() + x - 1) as usize];
                }
                if y > 0 {
                    ldiff += result[((y - 1) * a.width() + x) as usize];
                }
                if x > 0 && y > 0 {
                    ldiff -= result[((y - 1) * a.width() + x - 1) as usize];
                }

                result.push(ldiff);
            }
        }

        result
    }

    pub fn apply(&mut self, image: RgbaImage) -> RgbaImage {
        let mut progress = ProgressBar::new(self.iterations as u64);
        progress.format("|#--|");

        let mut destination = RgbaImage::new(image.width(), image.height());

        for _ in 0..self.iterations {
            let difference_lut = Geometrify::calculate_difference_lut(&image, &destination);

            let primitives = (0..self.samples)
                .map(|_| self.generate_primitive(image.width(), image.height()))
                .map(
                    |mut p| {
                        p.span_div_save();
                        p
                    }
                )
                .collect::<Vec<Triangle>>();
            let min_primitive = primitives
                .par_iter()
                .map(
                    |primitive| {
                        let mut prim = *primitive;
                        prim.color = Some(Geometrify::calculate_color(&image, &prim));
                        (prim,
                         Geometrify::calculate_difference(
                            &image,
                            &destination,
                            &difference_lut,
                            &prim,
                        ))
                    }
                )
                .min_by_key(|tup| tup.1);

            Geometrify::add_to_image(
                &mut destination,
                &min_primitive.expect("no fitting triangle found").0,
            );
            progress.inc();
        }
        progress.finish_print("done");

        destination
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>use std::io::{Read,Write};
use std::ascii::AsciiExt;

#[derive(Debug)]
struct Bom ( u8, u8, u8, u8 );

#[derive(Clone,Debug)]
enum Flavour {
    UCS,
    UTF,
    EBCDIC,
    ASCII,
    Unknown,
}

#[derive(Clone,Debug)]
enum ByteOrder {
    BigEndian,
    LittleEndian,
    Unusual2143,
    Unusual3412,
    NotApplicable
}

#[derive(Clone,Debug)]
enum Width {
    EightBit     = 8,
    SixteenBit   = 16,
    ThirtyTwoBit = 32
}

#[derive(Clone,Debug)]
struct Descriptor (
    Flavour,
    Width,
    ByteOrder,
);

// 32-Bit Encodings
const UCS_4_BE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const UCS_4_LE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const UCS_4_2143: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual2143);
const UCS_4_3412: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual3412);

// 16-Bit Encodings
const UTF_16_BE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::BigEndian);
const UTF_16_LE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::LittleEndian);

const UTF_8: Descriptor = Descriptor(Flavour::UTF, Width::EightBit, ByteOrder::NotApplicable);
const EBCDIC: Descriptor = Descriptor(Flavour::EBCDIC, Width::EightBit, ByteOrder::NotApplicable);

// ASCII compatible encodings
const ASCII_32BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const ASCII_32BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const ASCII_16BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::BigEndian);
const ASCII_16BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::LittleEndian);
const ASCII_8BIT: Descriptor = Descriptor(Flavour::ASCII, Width::EightBit, ByteOrder::NotApplicable);

pub fn detect<R: Read>(reader: &mut R, hint: Option<String>) -> Vec<String> {
    // Read the first 4 bytes and see if they help
    let mut first_four_bytes = [0u8; 4];
    match reader.read(&mut first_four_bytes) {
        Ok(bytes_read) => assert_eq!(bytes_read, 4),
        Err(e) => panic!(e)
    };

    let bom = Bom(
        first_four_bytes[0],
        first_four_bytes[1],
        first_four_bytes[2],
        first_four_bytes[3]
    );

    // http://www.w3.org/TR/2004/REC-xml-20040204/#sec-guessing-no-ext-info
    // Can do below without the Bom type if slice pattern syntax becomes non-experimental
    // let possible = match first_four_bytes {
    //     // With Byte Order Mark
    //     [0x00, 0x00, 0xFE, 0xFF]             => Some("UCS-4BE"),
    //     [0xFF, 0xFE, 0x00, 0x00]             => Some("UCS-4LE"),
    //     [0x00, 0x00, 0xFF, 0xFE]             => Some("UCS-4OE"),
    //     [0xFE, 0xFF, 0x00, 0x00]             => Some("UCS-4EO"),
    //     [0xFE, 0xFF, c, d] if c > 0 && d > 0 => Some("UTF-16BE"),
    //     [0xFF, 0xFE, c, d] if c > 0 && d > 0 => Some("UCS-16LE"),
    //     [0xEF, 0xBB, 0xBF, _   ]             => Some("UTF-8"),

    //     //  Without Byte Order Mark
    //     [0x00, 0x00, 0x00, 0x3C] |
    //     [0x3C, 0x00, 0x00, 0x00] |
    //     [0x00, 0x00, 0x3C, 0x00] |
    //     [0x00, 0x3C, 0x00, 0x00]             => Some("32-bit"),
    //     [0x00, 0x3C, 0x00, 0x3F]             => Some("16-bit Big Endian"),
    //     [0x3C, 0x00, 0x3F, 0x00]             => Some("16-bit Little Endian"),
    //     [0x3C, 0x3F, 0x78, 0x6D]             => Some("8-bit"),
    //     [0x4C, 0x6F, 0xA7, 0x94]             => Some("EBCDIC"),
    //     // This may be UTF-8 without an encoding declaration as this is not required
    //     // for UTF-8
    //     _                                    => Some("Other"),
    // };

    let possible = match bom {
        // With Byte Order Mark
        Bom(0x00, 0x00, 0xFE, 0xFF)                   => Some(UCS_4_BE),
        Bom(0xFF, 0xFE, 0x00, 0x00)                   => Some(UCS_4_LE),
        Bom(0x00, 0x00, 0xFF, 0xFE)                   => Some(UCS_4_2143),
        Bom(0xFE, 0xFF, 0x00, 0x00)                   => Some(UCS_4_3412),
        Bom(0xFE, 0xFF, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_BE),
        Bom(0xFF, 0xFE, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_LE),
        Bom(0xEF, 0xBB, 0xBF, _   )                   => Some(UTF_8),

        //  Without Byte Order Mark
        Bom(0x00, 0x00, 0x00, 0x3C)                   => Some(ASCII_32BIT_BE),
        Bom(0x3C, 0x00, 0x00, 0x00)                   => Some(ASCII_32BIT_LE),
        Bom(0x00, 0x00, 0x3C, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual2143)),
        Bom(0x00, 0x3C, 0x00, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual3412)),
        Bom(0x00, 0x3C, 0x00, 0x3F)                   => Some(ASCII_16BIT_BE),
        Bom(0x3C, 0x00, 0x3F, 0x00)                   => Some(ASCII_16BIT_LE),
        Bom(0x3C, 0x3F, 0x78, 0x6D)                   => Some(ASCII_8BIT),
        Bom(0x4C, 0x6F, 0xA7, 0x94)                   => Some(EBCDIC),
        // This may be UTF-8 without an encoding declaration as this is not required
        // for UTF-8
        _                                             => None,
    };

    // Now that byte size may have been determined try reading the first 512ish bytes to read an
    // encoding declaration
    let mut buf = [0u8; 512];
    let bytes_read = reader.read(&mut buf).unwrap();

    let mut candidates = Vec::with_capacity(3);

    // Look for encoding="", charset="?"?
    search("encoding=", &buf.to_vec(), possible.clone())
        .or_else(|| search("charset=", &buf.to_vec(), possible.clone()))
        .map(|encoding| normalise(&encoding))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.clone())));

    // Consider hint
    hint.map(|hint| normalise(&hint))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.clone())));

    // Include info from BOM detection
    let from_bom = match possible {
        Some(UCS_4_LE) => Some("ucs-4le"),
        Some(UCS_4_BE) => Some("ucs-4be"),
        Some(UTF_16_LE) => Some("utf-16le"),
        Some(UTF_16_BE) => Some("utf-16be"),
        Some(Descriptor(Flavour::UTF, Width::EightBit, _)) => Some("utf-8"),
        Some(EBCDIC) => Some("ebcdic"),
        _ => None
    }.map(|encoding| push_if_not_contains(&mut candidates, encoding.to_string()));

    // Otherwise test if UTF-8
    if candidates.is_empty() && String::from_utf8(buf.to_vec()).is_ok() {
        candidates.push("utf-8".to_string());
    }

    return candidates;
}

fn normalise(encoding: &String) -> String {
    encoding.to_ascii_lowercase()
        .replace("us-ascii", "ascii")
        .replace("shift-jis", "shift_jis")
}

fn push_if_not_contains<T: PartialEq>(vec: &mut Vec<T>, item: T) {
    if !vec.contains(&item) {
        vec.push(item);
    }
}

fn endianify(encoding: &str, descriptor: Option<Descriptor>) -> String {
    let Descriptor(ref flavour, ref width, ref order) = descriptor.unwrap_or(ASCII_8BIT);

    match encoding {
        "utf-16" => {
            match *order {
                ByteOrder::LittleEndian => "utf-16le".to_string(),
                ByteOrder::BigEndian    => "utf-16be".to_string(),
                _ => encoding.to_string()
            }
        },
        _ => encoding.to_string()
    }
}

fn search(needle: &str, haystack: &Vec<u8>, descriptor: Option<Descriptor>) -> Option<String> {
    let Descriptor(ref flavour, ref width, ref order) = descriptor.unwrap_or(ASCII_8BIT);
    let chunk_size = (width.clone() as usize) / 8;
    let needle_bytes = needle.as_bytes();

    let mut index = match *order {
        ByteOrder::NotApplicable | ByteOrder::LittleEndian  => 0,
        ByteOrder::BigEndian => chunk_size - 1,
        ByteOrder::Unusual2143 => 2,
        ByteOrder::Unusual3412 => 1,
    };

    let mut ascii_bytes = Vec::with_capacity(haystack.len() / chunk_size);
    while index < haystack.len() {
        ascii_bytes.push(haystack[index]);
        index += chunk_size;
    }

    let ascii_haystack = String::from_utf8_lossy(&ascii_bytes);

    ascii_haystack.find(needle).map(|pos| {
        // Skip to the matching byte + length of the needle
        ascii_haystack[pos + needle.len()..].chars()
            .skip_while(|char| *char == '"' || *char == '\'')
            .take_while(|char| *char != '"' && *char != '\'').collect()
    })
}

<commit_msg>Handle utf-8 declared as utf8<commit_after>use std::io::{Read,Write};
use std::ascii::AsciiExt;

#[derive(Debug)]
struct Bom ( u8, u8, u8, u8 );

#[derive(Clone,Debug)]
enum Flavour {
    UCS,
    UTF,
    EBCDIC,
    ASCII,
    Unknown,
}

#[derive(Clone,Debug)]
enum ByteOrder {
    BigEndian,
    LittleEndian,
    Unusual2143,
    Unusual3412,
    NotApplicable
}

#[derive(Clone,Debug)]
enum Width {
    EightBit     = 8,
    SixteenBit   = 16,
    ThirtyTwoBit = 32
}

#[derive(Clone,Debug)]
struct Descriptor (
    Flavour,
    Width,
    ByteOrder,
);

// 32-Bit Encodings
const UCS_4_BE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const UCS_4_LE: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const UCS_4_2143: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual2143);
const UCS_4_3412: Descriptor = Descriptor(Flavour::UCS, Width::ThirtyTwoBit, ByteOrder::Unusual3412);

// 16-Bit Encodings
const UTF_16_BE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::BigEndian);
const UTF_16_LE: Descriptor = Descriptor(Flavour::UTF, Width::SixteenBit, ByteOrder::LittleEndian);

const UTF_8: Descriptor = Descriptor(Flavour::UTF, Width::EightBit, ByteOrder::NotApplicable);
const EBCDIC: Descriptor = Descriptor(Flavour::EBCDIC, Width::EightBit, ByteOrder::NotApplicable);

// ASCII compatible encodings
const ASCII_32BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::BigEndian);
const ASCII_32BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::LittleEndian);
const ASCII_16BIT_BE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::BigEndian);
const ASCII_16BIT_LE: Descriptor = Descriptor(Flavour::Unknown, Width::SixteenBit, ByteOrder::LittleEndian);
const ASCII_8BIT: Descriptor = Descriptor(Flavour::ASCII, Width::EightBit, ByteOrder::NotApplicable);

pub fn detect<R: Read>(reader: &mut R, hint: Option<String>) -> Vec<String> {
    // Read the first 4 bytes and see if they help
    let mut first_four_bytes = [0u8; 4];
    match reader.read(&mut first_four_bytes) {
        Ok(bytes_read) => assert_eq!(bytes_read, 4),
        Err(e) => panic!(e)
    };

    let bom = Bom(
        first_four_bytes[0],
        first_four_bytes[1],
        first_four_bytes[2],
        first_four_bytes[3]
    );

    // http://www.w3.org/TR/2004/REC-xml-20040204/#sec-guessing-no-ext-info
    // Can do below without the Bom type if slice pattern syntax becomes non-experimental
    // let possible = match first_four_bytes {
    //     // With Byte Order Mark
    //     [0x00, 0x00, 0xFE, 0xFF]             => Some("UCS-4BE"),
    //     [0xFF, 0xFE, 0x00, 0x00]             => Some("UCS-4LE"),
    //     [0x00, 0x00, 0xFF, 0xFE]             => Some("UCS-4OE"),
    //     [0xFE, 0xFF, 0x00, 0x00]             => Some("UCS-4EO"),
    //     [0xFE, 0xFF, c, d] if c > 0 && d > 0 => Some("UTF-16BE"),
    //     [0xFF, 0xFE, c, d] if c > 0 && d > 0 => Some("UCS-16LE"),
    //     [0xEF, 0xBB, 0xBF, _   ]             => Some("UTF-8"),

    //     //  Without Byte Order Mark
    //     [0x00, 0x00, 0x00, 0x3C] |
    //     [0x3C, 0x00, 0x00, 0x00] |
    //     [0x00, 0x00, 0x3C, 0x00] |
    //     [0x00, 0x3C, 0x00, 0x00]             => Some("32-bit"),
    //     [0x00, 0x3C, 0x00, 0x3F]             => Some("16-bit Big Endian"),
    //     [0x3C, 0x00, 0x3F, 0x00]             => Some("16-bit Little Endian"),
    //     [0x3C, 0x3F, 0x78, 0x6D]             => Some("8-bit"),
    //     [0x4C, 0x6F, 0xA7, 0x94]             => Some("EBCDIC"),
    //     // This may be UTF-8 without an encoding declaration as this is not required
    //     // for UTF-8
    //     _                                    => Some("Other"),
    // };

    let possible = match bom {
        // With Byte Order Mark
        Bom(0x00, 0x00, 0xFE, 0xFF)                   => Some(UCS_4_BE),
        Bom(0xFF, 0xFE, 0x00, 0x00)                   => Some(UCS_4_LE),
        Bom(0x00, 0x00, 0xFF, 0xFE)                   => Some(UCS_4_2143),
        Bom(0xFE, 0xFF, 0x00, 0x00)                   => Some(UCS_4_3412),
        Bom(0xFE, 0xFF, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_BE),
        Bom(0xFF, 0xFE, c   , d   ) if c > 0 || d > 0 => Some(UTF_16_LE),
        Bom(0xEF, 0xBB, 0xBF, _   )                   => Some(UTF_8),

        //  Without Byte Order Mark
        Bom(0x00, 0x00, 0x00, 0x3C)                   => Some(ASCII_32BIT_BE),
        Bom(0x3C, 0x00, 0x00, 0x00)                   => Some(ASCII_32BIT_LE),
        Bom(0x00, 0x00, 0x3C, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual2143)),
        Bom(0x00, 0x3C, 0x00, 0x00)                   => Some(Descriptor(Flavour::Unknown, Width::ThirtyTwoBit, ByteOrder::Unusual3412)),
        Bom(0x00, 0x3C, 0x00, 0x3F)                   => Some(ASCII_16BIT_BE),
        Bom(0x3C, 0x00, 0x3F, 0x00)                   => Some(ASCII_16BIT_LE),
        Bom(0x3C, 0x3F, 0x78, 0x6D)                   => Some(ASCII_8BIT),
        Bom(0x4C, 0x6F, 0xA7, 0x94)                   => Some(EBCDIC),
        // This may be UTF-8 without an encoding declaration as this is not required
        // for UTF-8
        _                                             => None,
    };

    // Now that byte size may have been determined try reading the first 512ish bytes to read an
    // encoding declaration
    let mut buf = [0u8; 512];
    let bytes_read = reader.read(&mut buf).unwrap();

    let mut candidates = Vec::with_capacity(3);

    // Look for encoding="", charset="?"?
    search("encoding=", &buf.to_vec(), possible.clone())
        .or_else(|| search("charset=", &buf.to_vec(), possible.clone()))
        .map(|encoding| normalise(&encoding))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.clone())));

    // Consider hint
    hint.map(|hint| normalise(&hint))
        .map(|encoding| push_if_not_contains(&mut candidates, endianify(&encoding, possible.clone())));

    // Include info from BOM detection
    let from_bom = match possible {
        Some(UCS_4_LE) => Some("ucs-4le"),
        Some(UCS_4_BE) => Some("ucs-4be"),
        Some(UTF_16_LE) => Some("utf-16le"),
        Some(UTF_16_BE) => Some("utf-16be"),
        Some(Descriptor(Flavour::UTF, Width::EightBit, _)) => Some("utf-8"),
        Some(EBCDIC) => Some("ebcdic"),
        _ => None
    }.map(|encoding| push_if_not_contains(&mut candidates, encoding.to_string()));

    // Otherwise test if UTF-8
    if candidates.is_empty() && String::from_utf8(buf.to_vec()).is_ok() {
        candidates.push("utf-8".to_string());
    }

    return candidates;
}

fn normalise(encoding: &String) -> String {
    encoding.to_ascii_lowercase()
        .replace("us-ascii", "ascii")
        .replace("utf8", "utf-8")
        .replace("shift-jis", "shift_jis")
}

fn push_if_not_contains<T: PartialEq>(vec: &mut Vec<T>, item: T) {
    if !vec.contains(&item) {
        vec.push(item);
    }
}

fn endianify(encoding: &str, descriptor: Option<Descriptor>) -> String {
    let Descriptor(ref flavour, ref width, ref order) = descriptor.unwrap_or(ASCII_8BIT);

    match encoding {
        "utf-16" => {
            match *order {
                ByteOrder::LittleEndian => "utf-16le".to_string(),
                ByteOrder::BigEndian    => "utf-16be".to_string(),
                _ => encoding.to_string()
            }
        },
        _ => encoding.to_string()
    }
}

fn search(needle: &str, haystack: &Vec<u8>, descriptor: Option<Descriptor>) -> Option<String> {
    let Descriptor(ref flavour, ref width, ref order) = descriptor.unwrap_or(ASCII_8BIT);
    let chunk_size = (width.clone() as usize) / 8;
    let needle_bytes = needle.as_bytes();

    let mut index = match *order {
        ByteOrder::NotApplicable | ByteOrder::LittleEndian  => 0,
        ByteOrder::BigEndian => chunk_size - 1,
        ByteOrder::Unusual2143 => 2,
        ByteOrder::Unusual3412 => 1,
    };

    let mut ascii_bytes = Vec::with_capacity(haystack.len() / chunk_size);
    while index < haystack.len() {
        ascii_bytes.push(haystack[index]);
        index += chunk_size;
    }

    let ascii_haystack = String::from_utf8_lossy(&ascii_bytes);

    ascii_haystack.find(needle).map(|pos| {
        // Skip to the matching byte + length of the needle
        ascii_haystack[pos + needle.len()..].chars()
            .skip_while(|char| *char == '"' || *char == '\'')
            .take_while(|char| *char != '"' && *char != '\'').collect()
    })
}

<|endoftext|>


<commit_before>// The shift characters are stored as nulls, as the conversion code doesn't
// care what value they have.  WRU? maps to ASCII ENQ (\x05), I think.
const Ita2Letters = b"\0E\nA SIU\rDRJNFCKTZLWHYPQOBG\0MXV\0";
const Ita2Figures = b"\03\n- \x0787\r\x054',!:(5\")2#6019?&\0./;\0"

#[test]
fn it_works() {
}
<commit_msg>Stop and think and make it compile first<commit_after>// The shift characters are stored as nulls, as the conversion code doesn't
// care what value they have.  WRU? maps to ASCII ENQ (\x05), I think.
const ITA2: (&'static [u8], &'static [u8]) =
            (b"\0E\nA SIU\rDRJNFCKTZLWHYPQOBG\0MXV\0",
             b"\03\n- \x0787\r\x054',!:(5\")2#6019?&\0./;\0");

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>use node;
use time;
use std::collections::VecDeque;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new();
   let beta  = node::Node::new();
   let beta_seed = beta.local_info();

   // Bootstrapping alpha:
   alpha.bootstrap(beta_seed);

   // Before sending the ping, beta does not know about alpha.
   assert!(beta.resources.table.specific_node(&alpha.resources.id).is_none());

   // Alpha pings beta.
   assert_eq!(alpha.ping(beta.resources.id.clone()), node::PingResult::Alive);

   // And beta now knows of alpha
   assert!(beta.resources.table.specific_node(&alpha.resources.id).is_some());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();
   for rpc in receptions {
      // nothing is happening, so this should time out in around a second (not necessarily precise)
      panic!();
   }
   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn chained_node_find() {
   let mut nodes: VecDeque<node::Node> = (0..10).map(|_| { node::Node::new() }).collect();

   // We inform each node of the existance of the next three.
   for (((alpha, beta),gamma), delta) in nodes.iter()
                                              .zip(nodes.iter().skip(1))
                                              .zip(nodes.iter().skip(3))
                                              .zip(nodes.iter().skip(5))
   {
      alpha.resources.table.insert_node(beta.local_info());
      alpha.resources.table.insert_node(gamma.local_info());
      alpha.resources.table.insert_node(delta.local_info());
   }

   // Head finds tail
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   assert_eq!(head.find_node(tail.id()).unwrap(), tail.local_info());
}
<commit_msg>Fixed test condition. Chained lookup now working<commit_after>use node;
use time;
use std::collections::VecDeque;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new();
   let beta  = node::Node::new();
   let beta_seed = beta.local_info();

   // Bootstrapping alpha:
   alpha.bootstrap(beta_seed);

   // Before sending the ping, beta does not know about alpha.
   assert!(beta.resources.table.specific_node(&alpha.resources.id).is_none());

   // Alpha pings beta.
   assert_eq!(alpha.ping(beta.resources.id.clone()), node::PingResult::Alive);

   // And beta now knows of alpha
   assert!(beta.resources.table.specific_node(&alpha.resources.id).is_some());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();
   for rpc in receptions {
      // nothing is happening, so this should time out in around a second (not necessarily precise)
      panic!();
   }
   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn chained_node_find() {
   let mut nodes: VecDeque<node::Node> = (0..10).map(|_| { node::Node::new() }).collect();

   // We inform each node of the existance of the next three.
   for i in 1..4 {
      for (alpha, beta) in nodes.iter().zip(nodes.iter().skip(i)) {
         alpha.resources.table.insert_node(beta.local_info());
      }
   }

   // Head finds tail
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   assert_eq!(head.find_node(tail.id()).unwrap(), tail.local_info());
}
<|endoftext|>


<commit_before>
#![feature(phase)]

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    match key.len() {
        0 => source.to_vec(),
        1 => xor_byte(source, key[0]),
        _ => xor_sequence(source, key),
    }
}

fn xor_byte(source: &[u8], byte: u8) -> Vec<u8> {
    source.iter().map(|&a| a ^ byte).collect()
}

fn xor_sequence(source: &[u8], key: &[u8]) -> Vec<u8> {
    let key_iter = InfiniteByteIterator::new(key);
    source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
}

struct InfiniteByteIterator<'a> {
    bytes: &'a [u8],
    index: uint
}

impl<'a> InfiniteByteIterator<'a> {
    pub fn new(bytes: &'a [u8]) -> InfiniteByteIterator<'a> {
        InfiniteByteIterator {
            bytes: bytes,
            index: 0
        }
    }
}

impl<'a> Iterator<u8> for InfiniteByteIterator<'a> {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(index: uint, count: uint) -> uint {
    if index + 1 < count { index + 1 } else { 0 }
}

#[cfg(test)]
mod test {
    #[phase(plugin)] extern crate stainless;
    pub use super::xor;

    describe! xor {
        it "should return right result" {
            let source = [0, 1, 2, 3];
            let key = [34, 52];
            assert!(xor(source, key).as_slice() == [34, 53, 32, 55]);
        }

        it "should return right result with one byte xor" {
            let source = [0, 1, 2, 3];
            let key = [47];
            assert!(xor(source, key).as_slice() == [47, 46, 45, 44]);
        }

        it "should return source if key is empty" {
            let source = [0, 1, 2, 3];
            let key = [];
            assert!(xor(source, key).as_slice() == [0, 1, 2, 3]);
        }

        it "should return empty result if source is empty" {
            let source = [];
            let key = [45, 32, 56];
            assert!(xor(source, key).as_slice() == []);
        }
    }
}
<commit_msg>Added new function to xor with single byte.<commit_after>
#![feature(phase)]

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    match key.len() {
        0 => source.to_vec(),
        1 => xor_byte(source, key[0]),
        _ => {
            let key_iter = InfiniteByteIterator::new(key);
            source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
        },
    }
}

pub fn xor_byte(source: &[u8], byte: u8) -> Vec<u8> {
    source.iter().map(|&a| a ^ byte).collect()
}

struct InfiniteByteIterator<'a> {
    bytes: &'a [u8],
    index: uint
}

impl<'a> InfiniteByteIterator<'a> {
    pub fn new(bytes: &'a [u8]) -> InfiniteByteIterator<'a> {
        InfiniteByteIterator {
            bytes: bytes,
            index: 0
        }
    }
}

impl<'a> Iterator<u8> for InfiniteByteIterator<'a> {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(index: uint, count: uint) -> uint {
    if index + 1 < count { index + 1 } else { 0 }
}

#[cfg(test)]
mod test {
    #[phase(plugin)] extern crate stainless;

    pub use super::{
        xor,
        xor_byte,
    };

    describe! xor {
        it "should return right result" {
            let source = [0, 1, 2, 3];
            let key = [34, 52];
            assert!(xor(source, key).as_slice() == [34, 53, 32, 55]);
        }

        it "should return right result with one byte xor" {
            let source = [0, 1, 2, 3];
            let key = [47];
            assert!(xor(source, key).as_slice() == [47, 46, 45, 44]);
        }

        it "should return source if key is empty" {
            let source = [0, 1, 2, 3];
            let key = [];
            assert!(xor(source, key).as_slice() == [0, 1, 2, 3]);
        }

        it "should return empty result if source is empty" {
            let source = [];
            let key = [45, 32, 56];
            assert!(xor(source, key).as_slice() == []);
        }
    }

    describe! xor_byte {
        it "should return right result" {
            let source = [0, 1, 2, 3];
            assert!(xor_byte(source, 23).as_slice() == [23, 22, 21, 20]);
        }
    }
}
<|endoftext|>