<commit_before>//! Compute timezones of points on the Earth.
//!
//! This is a direct port of
//! [bradfitz/latlong](https://github.com/bradfitz/latlong), and hence
//! the same bonuses/caveats apply:
//!
//! > It tries to have a small binary size (~360 KB), low memory footprint
//! > (~1 MB), and incredibly fast lookups (...). It does not
//! > try to be perfectly accurate when very close to borders.
//!
//! A time-zone lookup with this library takes on the order of 150 ns.
//!
//! [Source](https://github.com/huonw/tz-search).
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! tz-search = "0.1"
//! ```
//!
//! # Examples
//!
//! ```rust
//! assert_eq!(tz_search::lookup(-33.79, 151.17).unwrap(),
//!            "Australia/Sydney");
//!
//! // in the ocean
//! assert_eq!(tz_search::lookup(0.0, 0.0), None);
//! ```

#![cfg_attr(all(test, feature = "experimental"), feature(test))]

extern crate flate2;
extern crate rustc_serialize;
extern crate byteorder;

use std::{cmp, mem, sync};
use std::sync::atomic;
use std::io::prelude::*;
use std::io::BufReader;
use byteorder::{BigEndian, ReadBytesExt};

#[allow(warnings)]
mod tables;

/// Attempt to compute the timezone that the point `lat`, `long`
/// lies in.
///
/// The latitude `lat` should lie in the range `[-90, 90]` with
/// negative representing south, and the longitude should lie in
/// the range `[-180, 180]` with negative representing west. This
/// will fail (return `None`) if the point lies in the ocean.
///
/// # Panics
///
/// `lookup` will panic if either of the two ranges above are
/// violated.
///
/// # Examples
///
/// ```rust
/// assert_eq!(tz_search::lookup(-33.79, 151.17).unwrap(),
///            "Australia/Sydney");
///
/// // in the ocean
/// assert_eq!(tz_search::lookup(0.0, 0.0), None);
/// ```
pub fn lookup(lat: f64, lon: f64) -> Option<String> {
    static SHARED: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
    static ONCE: sync::Once = sync::ONCE_INIT;

    ONCE.call_once(|| {
        let s = Box::new(TzSearch::new());
        SHARED.store(unsafe {mem::transmute(s)}, atomic::Ordering::Relaxed);
    });

    let ptr = SHARED.load(atomic::Ordering::Relaxed);
    assert!(ptr != 0);
    let s = unsafe {&*(ptr as *const TzSearch)};
    s.lookup(lat, lon)
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
struct TileKey(u32);
impl TileKey {
    fn new(size: u8, x: u16, y: u16) -> TileKey {
        let size = size as u32;
        let x = x as u32;
        let y = y as u32;
        TileKey((size % 8) << 28 | (y % (1<<14)) << 14 | (x % (1<<14)))
    }
}

#[derive(Debug)]
struct TileLooker {
    tile: TileKey,
    idx: u16,
}
#[derive(Debug)]
struct ZoomLevel {
    tiles: Vec<TileLooker>
}
#[derive(Debug)]

/// All the information required for efficient time-zone lookups.
///
/// Unless you need absolutely strict control over memory use, you
/// probably want to call the top-level `lookup`, rather than going
/// via this.
pub struct TzSearch {
    leaves: Vec<Zone>,
    zoom_levels: Vec<ZoomLevel>,
}

enum Zone {
    StaticZone(String),
    OneBitTile([u16; 2], [u8; 8]),
    Pixmap([u8; 128])
}
impl std::fmt::Debug for Zone {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Zone::StaticZone(ref s) => write!(f, "StaticZone({:?})", s),
            Zone::OneBitTile(a, b) => write!(f, "OneBitTile({:?}, {:?})", &a[..], &b[..]),
            Zone::Pixmap(c) => write!(f, "Pixmap({:?})", &c[..]),
        }
    }
}

impl TzSearch {
    /// Create a new `TzSearch`.
    ///
    /// This is very expensive: the initialisation routine takes a
    /// long time (15 ms, compared to 150 *nano*seconds for `lookup`
    /// itself), and the resulting structure uses a lot of
    /// memory. Hence, this should be called as rarely as possible.
    ///
    /// The free-standing `lookup` function internally manages
    /// creating exactly one of these, and should be preferred.
    pub fn new() -> TzSearch {
        let mut zoom_levels = vec![];
        for data in tables::REV_ZOOM_LEVELS.iter().rev() {
            let unb64d = rustc_serialize::base64::FromBase64::from_base64(*data).unwrap();
            let mut slurp = vec![];
            flate2::read::GzDecoder::new(&*unb64d).unwrap().read_to_end(&mut slurp).unwrap();
            assert_eq!(slurp.len() % 6, 0);
            let count = slurp.len() / 6;

            let mut slurp = &slurp[..];
            let mut tiles = Vec::with_capacity(count);
            for _ in 0..count {
                tiles.push(TileLooker {
                    tile: TileKey(slurp.read_u32::<BigEndian>().unwrap()),
                    idx: slurp.read_u16::<BigEndian>().unwrap(),
                })
            }

            zoom_levels.push(ZoomLevel { tiles: tiles })
        }
        let mut leaves = Vec::with_capacity(tables::NUM_LEAVES);
        let unb64d = rustc_serialize::base64::FromBase64::from_base64(tables::UNIQUE_LEAVES_PACKED)
            .unwrap();
        let mut ungz = BufReader::new(flate2::read::GzDecoder::new(&*unb64d).unwrap());
        let mut buf = [0; 128];
        for _ in 0..tables::NUM_LEAVES {
            let zone = match ungz.read_u8().unwrap() {
                b'S' => {
                    let mut zone_name = vec![];
                    ungz.read_until(0, &mut zone_name).unwrap();
                    if zone_name.last() == Some(&0) { zone_name.pop(); }
                    Zone::StaticZone(String::from_utf8(zone_name).unwrap())
                }
                b'2' => {
                    let idx = [ungz.read_u16::<BigEndian>().unwrap(),
                               ungz.read_u16::<BigEndian>().unwrap()];
                    let bits = ungz.read_u64::<BigEndian>().unwrap();
                    let mut rows = [0; 8];
                    for (y, place) in rows.iter_mut().enumerate() {
                        for x in 0..8 {
                            if bits & (1 << (y * 8 + x)) != 0 {
                                *place |= 1 << x
                            }
                        }
                    }
                    Zone::OneBitTile(idx, rows)
                }
                b'P' => {
                    let mut i = 0;
                    while i < 128 {
                        i += ungz.read(&mut buf[i..]).unwrap()
                    }
                    Zone::Pixmap(buf)
                }
                _ => panic!("unknown leaf type")
            };
            leaves.push(zone)
        }

        TzSearch {
            zoom_levels: zoom_levels,
            leaves: leaves
        }
    }

    /// Attempt to compute the timezone that the point `lat`, `long`
    /// lies in.
    ///
    /// The latitude `lat` should lie in the range `[-90, 90]` with
    /// negative representing south, and the longitude should lie in
    /// the range `[-180, 180]` with negative representing west. This
    /// will fail (return `None`) if the point lies in the ocean.
    ///
    /// See also: the `lookup` function at the top-level.
    ///
    /// # Panics
    ///
    /// `lookup` will panic if either of the two ranges above are
    /// violated.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let s = tz_search::TzSearch::new();
    /// let (lat, long) = (-33.8885, 151.1908);
    /// assert_eq!(s.lookup(lat, long).unwrap(),
    ///            "Australia/Sydney");
    /// ```
    pub fn lookup(&self, lat: f64, long: f64) -> Option<String> {
        fn clamp(x: isize, lim: isize) -> usize {
            cmp::max(0, cmp::min(lim * tables::DEG_PIXELS as isize, x)) as usize
        }
        assert!(-90.0 <= lat && lat <= 90.0);
        assert!(-180.0 <= long && long <= 180.0);
        let x = ((long + 180.0) * (tables::DEG_PIXELS as f64)) as isize;
        let y = ((90.0 - lat) * (tables::DEG_PIXELS as f64)) as isize;
        let x = clamp(x, 360);
        let y = clamp(y, 180);

        self.lookup_pixel(x, y)
    }
    fn lookup_pixel(&self, x: usize, y: usize) -> Option<String> {
        for level in (0..6).rev() {
            let shift = 3 + level;
            let xt = x >> shift;
            let yt = y >> shift;
            let tk = TileKey::new(level, xt as u16, yt as u16);
            if let Some(ret) = self.zoom_level_lookup(&self.zoom_levels[level as usize], x, y, tk) {
                return ret
            }
        }
        None
    }

    fn zone_lookup(&self, zone: &Zone, x: usize, y: usize, tk: TileKey) -> Option<Option<String>> {
        match *zone {
            Zone::StaticZone(ref s) => Some(Some(s.clone())),
            Zone::OneBitTile(idxs, rows) => {
                let idx = if rows[y & 7] & (1 << (x & 7)) != 0 {
                    idxs[1]
                } else {
                    idxs[0]
                };
                self.zone_lookup(&self.leaves[idx as usize], x, y, tk)
            }
            Zone::Pixmap(ref p) => {
                let xx = x & 7;
                let yy = y & 7;
                let i = 2 * (yy * 8 + xx);
                let idx = ((p[i] as usize) << 8) + p[i+1] as usize;
                const OCEAN_INDEX: usize = 0xFFFF;
                if idx == OCEAN_INDEX {
                    Some(None)
                } else {
                    self.zone_lookup(&self.leaves[idx], x, y, tk)
                }
            }
        }
    }

    fn zoom_level_lookup(&self, zl: &ZoomLevel, x: usize, y: usize, tk: TileKey)
                         -> Option<Option<String>>
    {
        let pos = zl.tiles.binary_search_by(|t| t.tile.cmp(&tk)).unwrap_or_else(|x| x);

        match zl.tiles.get(pos) {
            Some(tl) if tl.tile == tk => self.zone_lookup(&self.leaves[tl.idx as usize], x, y, tk),
            _ => None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{lookup, TzSearch};

    #[test]
    fn loads_ok() {
        let _searcher = TzSearch::new();
    }

    #[test]
    fn test_lookup_lat_long() {
        let searcher = TzSearch::new();
        let tests = [(37.7833, -122.4167, Some("America/Los_Angeles")),
                     (-33.8885, 151.1908, Some("Australia/Sydney")),
                     (0.0, 0.0, None)];
        for &(lat, lon, want) in &tests {
            let want = want.map(|s| s.to_string());
            assert_eq!(searcher.lookup(lat, lon), want);
            assert_eq!(lookup(lat, lon), want)
        }
    }
    #[test]
    fn test_lookup_pixel() {
        let searcher = TzSearch::new();
        let tests = [
            (9200, 2410, Some("Asia/Phnom_Penh")),
            (9047, 2488, Some("Asia/Phnom_Penh")),

            // one-bit leaf tile:
            (9290, 530, Some("Asia/Krasnoyarsk")),
            (9290, 531, Some("Asia/Yakutsk")),

            // four-bit tile:
            (2985, 1654, Some("America/Indiana/Vincennes")),
            (2986, 1654, Some("America/Indiana/Marengo")),
            (2986, 1655, Some("America/Indiana/Tell_City")),

            // Empty tile:
            (4000, 2000, None),

            // Big 1-color tile in ocean with island:
            (3687, 1845, Some("Atlantic/Bermuda")),
            // Same, but off Oregon coast:
            (1747, 1486, Some("America/Los_Angeles")),

            // Little solid tile:
            (2924, 2316, Some("America/Belize")),
            ];

        for &(lat, lon, ref want) in &tests {
            assert_eq!(searcher.lookup_pixel(lat, lon), want.map(|s| s.to_string()));
        }
    }
}

#[cfg(all(test, feature = "experimental"))]
mod benches {
    extern crate test;

    #[bench]
    pub fn init(b: &mut test::Bencher) {
        b.iter(|| super::TzSearch::new());
    }
    #[bench]
    pub fn lookup(b: &mut test::Bencher) {
        // ensure the searcher is initialised
        super::lookup(0., 0.);

        b.iter(|| {
            let mut count = 0;
            // step over the whole world, about half of these
            // 22438/43681 are real timezones, the rest are in the
            // ocean.
            for lat in -60..60 + 1 {
                for lng in -180..180 + 1 {
                    count += super::lookup(lat as f64, lng as f64).is_some() as usize
                }
            }
            count
        })
    }
}
<commit_msg>Change lat/long everywhere.<commit_after>//! Compute timezones of points on the Earth.
//!
//! This is a direct port of
//! [bradfitz/latlong](https://github.com/bradfitz/latlong), and hence
//! the same bonuses/caveats apply:
//!
//! > It tries to have a small binary size (~360 KB), low memory footprint
//! > (~1 MB), and incredibly fast lookups (...). It does not
//! > try to be perfectly accurate when very close to borders.
//!
//! A time-zone lookup with this library takes on the order of 150 ns.
//!
//! [Source](https://github.com/huonw/tz-search).
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! tz-search = "0.1"
//! ```
//!
//! # Examples
//!
//! ```rust
//! let (lat, long) = (-33.8885, 151.1908);
//! assert_eq!(tz_search::lookup(lat, long).unwrap(),
//!            "Australia/Sydney");
//!
//! // in the ocean
//! assert_eq!(tz_search::lookup(0.0, 0.0), None);
//! ```

#![cfg_attr(all(test, feature = "experimental"), feature(test))]

extern crate flate2;
extern crate rustc_serialize;
extern crate byteorder;

use std::{cmp, mem, sync};
use std::sync::atomic;
use std::io::prelude::*;
use std::io::BufReader;
use byteorder::{BigEndian, ReadBytesExt};

#[allow(warnings)]
mod tables;

/// Attempt to compute the timezone that the point `lat`, `long`
/// lies in.
///
/// The latitude `lat` should lie in the range `[-90, 90]` with
/// negative representing south, and the longitude should lie in
/// the range `[-180, 180]` with negative representing west. This
/// will fail (return `None`) if the point lies in the ocean.
///
/// # Panics
///
/// `lookup` will panic if either of the two ranges above are
/// violated.
///
/// # Examples
///
/// ```rust
/// let (lat, long) = (-33.8885, 151.1908);
/// assert_eq!(tz_search::lookup(lat, long).unwrap(),
///            "Australia/Sydney");
///
/// // in the ocean
/// assert_eq!(tz_search::lookup(0.0, 0.0), None);
/// ```
pub fn lookup(lat: f64, lon: f64) -> Option<String> {
    static SHARED: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
    static ONCE: sync::Once = sync::ONCE_INIT;

    ONCE.call_once(|| {
        let s = Box::new(TzSearch::new());
        SHARED.store(unsafe {mem::transmute(s)}, atomic::Ordering::Relaxed);
    });

    let ptr = SHARED.load(atomic::Ordering::Relaxed);
    assert!(ptr != 0);
    let s = unsafe {&*(ptr as *const TzSearch)};
    s.lookup(lat, lon)
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
struct TileKey(u32);
impl TileKey {
    fn new(size: u8, x: u16, y: u16) -> TileKey {
        let size = size as u32;
        let x = x as u32;
        let y = y as u32;
        TileKey((size % 8) << 28 | (y % (1<<14)) << 14 | (x % (1<<14)))
    }
}

#[derive(Debug)]
struct TileLooker {
    tile: TileKey,
    idx: u16,
}
#[derive(Debug)]
struct ZoomLevel {
    tiles: Vec<TileLooker>
}
#[derive(Debug)]

/// All the information required for efficient time-zone lookups.
///
/// Unless you need absolutely strict control over memory use, you
/// probably want to call the top-level `lookup`, rather than going
/// via this.
pub struct TzSearch {
    leaves: Vec<Zone>,
    zoom_levels: Vec<ZoomLevel>,
}

enum Zone {
    StaticZone(String),
    OneBitTile([u16; 2], [u8; 8]),
    Pixmap([u8; 128])
}
impl std::fmt::Debug for Zone {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Zone::StaticZone(ref s) => write!(f, "StaticZone({:?})", s),
            Zone::OneBitTile(a, b) => write!(f, "OneBitTile({:?}, {:?})", &a[..], &b[..]),
            Zone::Pixmap(c) => write!(f, "Pixmap({:?})", &c[..]),
        }
    }
}

impl TzSearch {
    /// Create a new `TzSearch`.
    ///
    /// This is very expensive: the initialisation routine takes a
    /// long time (15 ms, compared to 150 *nano*seconds for `lookup`
    /// itself), and the resulting structure uses a lot of
    /// memory. Hence, this should be called as rarely as possible.
    ///
    /// The free-standing `lookup` function internally manages
    /// creating exactly one of these, and should be preferred.
    pub fn new() -> TzSearch {
        let mut zoom_levels = vec![];
        for data in tables::REV_ZOOM_LEVELS.iter().rev() {
            let unb64d = rustc_serialize::base64::FromBase64::from_base64(*data).unwrap();
            let mut slurp = vec![];
            flate2::read::GzDecoder::new(&*unb64d).unwrap().read_to_end(&mut slurp).unwrap();
            assert_eq!(slurp.len() % 6, 0);
            let count = slurp.len() / 6;

            let mut slurp = &slurp[..];
            let mut tiles = Vec::with_capacity(count);
            for _ in 0..count {
                tiles.push(TileLooker {
                    tile: TileKey(slurp.read_u32::<BigEndian>().unwrap()),
                    idx: slurp.read_u16::<BigEndian>().unwrap(),
                })
            }

            zoom_levels.push(ZoomLevel { tiles: tiles })
        }
        let mut leaves = Vec::with_capacity(tables::NUM_LEAVES);
        let unb64d = rustc_serialize::base64::FromBase64::from_base64(tables::UNIQUE_LEAVES_PACKED)
            .unwrap();
        let mut ungz = BufReader::new(flate2::read::GzDecoder::new(&*unb64d).unwrap());
        let mut buf = [0; 128];
        for _ in 0..tables::NUM_LEAVES {
            let zone = match ungz.read_u8().unwrap() {
                b'S' => {
                    let mut zone_name = vec![];
                    ungz.read_until(0, &mut zone_name).unwrap();
                    if zone_name.last() == Some(&0) { zone_name.pop(); }
                    Zone::StaticZone(String::from_utf8(zone_name).unwrap())
                }
                b'2' => {
                    let idx = [ungz.read_u16::<BigEndian>().unwrap(),
                               ungz.read_u16::<BigEndian>().unwrap()];
                    let bits = ungz.read_u64::<BigEndian>().unwrap();
                    let mut rows = [0; 8];
                    for (y, place) in rows.iter_mut().enumerate() {
                        for x in 0..8 {
                            if bits & (1 << (y * 8 + x)) != 0 {
                                *place |= 1 << x
                            }
                        }
                    }
                    Zone::OneBitTile(idx, rows)
                }
                b'P' => {
                    let mut i = 0;
                    while i < 128 {
                        i += ungz.read(&mut buf[i..]).unwrap()
                    }
                    Zone::Pixmap(buf)
                }
                _ => panic!("unknown leaf type")
            };
            leaves.push(zone)
        }

        TzSearch {
            zoom_levels: zoom_levels,
            leaves: leaves
        }
    }

    /// Attempt to compute the timezone that the point `lat`, `long`
    /// lies in.
    ///
    /// The latitude `lat` should lie in the range `[-90, 90]` with
    /// negative representing south, and the longitude should lie in
    /// the range `[-180, 180]` with negative representing west. This
    /// will fail (return `None`) if the point lies in the ocean.
    ///
    /// See also: the `lookup` function at the top-level.
    ///
    /// # Panics
    ///
    /// `lookup` will panic if either of the two ranges above are
    /// violated.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let s = tz_search::TzSearch::new();
    /// let (lat, long) = (-33.8885, 151.1908);
    /// assert_eq!(s.lookup(lat, long).unwrap(),
    ///            "Australia/Sydney");
    /// ```
    pub fn lookup(&self, lat: f64, long: f64) -> Option<String> {
        fn clamp(x: isize, lim: isize) -> usize {
            cmp::max(0, cmp::min(lim * tables::DEG_PIXELS as isize, x)) as usize
        }
        assert!(-90.0 <= lat && lat <= 90.0);
        assert!(-180.0 <= long && long <= 180.0);
        let x = ((long + 180.0) * (tables::DEG_PIXELS as f64)) as isize;
        let y = ((90.0 - lat) * (tables::DEG_PIXELS as f64)) as isize;
        let x = clamp(x, 360);
        let y = clamp(y, 180);

        self.lookup_pixel(x, y)
    }
    fn lookup_pixel(&self, x: usize, y: usize) -> Option<String> {
        for level in (0..6).rev() {
            let shift = 3 + level;
            let xt = x >> shift;
            let yt = y >> shift;
            let tk = TileKey::new(level, xt as u16, yt as u16);
            if let Some(ret) = self.zoom_level_lookup(&self.zoom_levels[level as usize], x, y, tk) {
                return ret
            }
        }
        None
    }

    fn zone_lookup(&self, zone: &Zone, x: usize, y: usize, tk: TileKey) -> Option<Option<String>> {
        match *zone {
            Zone::StaticZone(ref s) => Some(Some(s.clone())),
            Zone::OneBitTile(idxs, rows) => {
                let idx = if rows[y & 7] & (1 << (x & 7)) != 0 {
                    idxs[1]
                } else {
                    idxs[0]
                };
                self.zone_lookup(&self.leaves[idx as usize], x, y, tk)
            }
            Zone::Pixmap(ref p) => {
                let xx = x & 7;
                let yy = y & 7;
                let i = 2 * (yy * 8 + xx);
                let idx = ((p[i] as usize) << 8) + p[i+1] as usize;
                const OCEAN_INDEX: usize = 0xFFFF;
                if idx == OCEAN_INDEX {
                    Some(None)
                } else {
                    self.zone_lookup(&self.leaves[idx], x, y, tk)
                }
            }
        }
    }

    fn zoom_level_lookup(&self, zl: &ZoomLevel, x: usize, y: usize, tk: TileKey)
                         -> Option<Option<String>>
    {
        let pos = zl.tiles.binary_search_by(|t| t.tile.cmp(&tk)).unwrap_or_else(|x| x);

        match zl.tiles.get(pos) {
            Some(tl) if tl.tile == tk => self.zone_lookup(&self.leaves[tl.idx as usize], x, y, tk),
            _ => None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{lookup, TzSearch};

    #[test]
    fn loads_ok() {
        let _searcher = TzSearch::new();
    }

    #[test]
    fn test_lookup_lat_long() {
        let searcher = TzSearch::new();
        let tests = [(37.7833, -122.4167, Some("America/Los_Angeles")),
                     (-33.8885, 151.1908, Some("Australia/Sydney")),
                     (0.0, 0.0, None)];
        for &(lat, lon, want) in &tests {
            let want = want.map(|s| s.to_string());
            assert_eq!(searcher.lookup(lat, lon), want);
            assert_eq!(lookup(lat, lon), want)
        }
    }
    #[test]
    fn test_lookup_pixel() {
        let searcher = TzSearch::new();
        let tests = [
            (9200, 2410, Some("Asia/Phnom_Penh")),
            (9047, 2488, Some("Asia/Phnom_Penh")),

            // one-bit leaf tile:
            (9290, 530, Some("Asia/Krasnoyarsk")),
            (9290, 531, Some("Asia/Yakutsk")),

            // four-bit tile:
            (2985, 1654, Some("America/Indiana/Vincennes")),
            (2986, 1654, Some("America/Indiana/Marengo")),
            (2986, 1655, Some("America/Indiana/Tell_City")),

            // Empty tile:
            (4000, 2000, None),

            // Big 1-color tile in ocean with island:
            (3687, 1845, Some("Atlantic/Bermuda")),
            // Same, but off Oregon coast:
            (1747, 1486, Some("America/Los_Angeles")),

            // Little solid tile:
            (2924, 2316, Some("America/Belize")),
            ];

        for &(lat, lon, ref want) in &tests {
            assert_eq!(searcher.lookup_pixel(lat, lon), want.map(|s| s.to_string()));
        }
    }
}

#[cfg(all(test, feature = "experimental"))]
mod benches {
    extern crate test;

    #[bench]
    pub fn init(b: &mut test::Bencher) {
        b.iter(|| super::TzSearch::new());
    }
    #[bench]
    pub fn lookup(b: &mut test::Bencher) {
        // ensure the searcher is initialised
        super::lookup(0., 0.);

        b.iter(|| {
            let mut count = 0;
            // step over the whole world, about half of these
            // 22438/43681 are real timezones, the rest are in the
            // ocean.
            for lat in -60..60 + 1 {
                for lng in -180..180 + 1 {
                    count += super::lookup(lat as f64, lng as f64).is_some() as usize
                }
            }
            count
        })
    }
}
<|endoftext|>


<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![doc = include_str!("../README.md")]
#![allow(unknown_lints)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]
#![allow(unknown_lints)]

#[cfg(feature = "debug")]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(feature = "unknown-ci")] {
        // This is used in CI to check that the build for unknown targets is compiling fine.
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    }
}

pub use common::{
    get_current_pid, AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, ProcessStatus,
    RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    cfg_if::cfg_if! {
        if #[cfg(all(not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
        {
            if _new_limit < 0 {
                _new_limit = 0;
            }
            let max = sys::system::get_max_nb_fds();
            if _new_limit > max {
                _new_limit = max;
            }
            if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
                // If files are already open, to be sure that the number won't be bigger when those
                // files are closed, we subtract the current number of opened files to the new
                // limit.
                let diff = max - **x;
                **x = _new_limit - diff;
                true
            } else {
                false
            }
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use crate::*;

    #[cfg(feature = "unknown-ci")]
    #[test]
    fn check_unknown_ci_feature() {
        assert!(!System::IS_SUPPORTED);
    }

    #[test]
    fn check_process_memory_usage() {
        let mut s = System::new();
        s.refresh_all();

        if System::IS_SUPPORTED {
            // No process should have 0 as memory usage.
            #[cfg(not(feature = "apple-sandbox"))]
            assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        } else {
            // There should be no process, but if there is one, its memory usage should be 0.
            assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        }
    }

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        assert_eq!(s.total_memory(), 0);
        assert_eq!(s.free_memory(), 0);
        assert_eq!(s.available_memory(), 0);
        assert_eq!(s.used_memory(), 0);
        assert_eq!(s.total_swap(), 0);
        assert_eq!(s.free_swap(), 0);
        assert_eq!(s.used_swap(), 0);

        s.refresh_memory();
        if System::IS_SUPPORTED {
            assert!(s.total_memory() > 0);
            assert!(s.used_memory() > 0);
            if s.total_swap() > 0 {
                // I think it's pretty safe to assume that there is still some swap left...
                assert!(s.free_swap() > 0);
            }
        } else {
            assert_eq!(s.total_memory(), 0);
            assert_eq!(s.used_memory(), 0);
            assert_eq!(s.total_swap(), 0);
            assert_eq!(s.free_swap(), 0);
        }
    }

    #[cfg(target_os = "linux")]
    #[test]
    fn check_processes_cpu_usage() {
        if !System::IS_SUPPORTED {
            return;
        }
        let mut s = System::new();

        s.refresh_processes();
        // All CPU usage will start at zero until the second refresh
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() == 0.0));

        // Wait a bit to update CPU usage values
        std::thread::sleep(std::time::Duration::from_millis(100));
        s.refresh_processes();
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
                && proc_.cpu_usage() <= (s.processors().len() as f32) * 100.0));
        assert!(s
            .processes()
            .iter()
            .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        assert!(s.users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_all();
        assert!(s.users().is_empty());

        let s = System::new_all();
        assert!(s.users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        let users = s.users();
        assert!(users.len() >= MIN_USERS);

        if System::IS_SUPPORTED {
            #[cfg(not(target_os = "windows"))]
            {
                let user = users
                    .iter()
                    .find(|u| u.name() == "root")
                    .expect("no root user");
                assert_eq!(*user.uid(), 0);
                assert_eq!(*user.gid(), 0);
                if let Some(user) = users.iter().find(|u| *u.gid() > 0) {
                    assert!(*user.uid() > 0);
                    assert!(*user.gid() > 0);
                }
            }
            #[cfg(not(target_os = "windows"))]
            {
                assert!(users.iter().filter(|u| *u.uid() > 0).count() > 0);
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.name().expect("Failed to get system name").is_empty());

            assert!(!s
                .kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s.os_version().expect("Failed to get os version").is_empty());

            assert!(!s
                .long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.host_name().expect("Failed to get host name").is_empty());
        }
    }

    #[test]
    fn check_refresh_process_return_value() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let _pid = get_current_pid().expect("Failed to get current PID");

            #[cfg(not(feature = "apple-sandbox"))]
            {
                let mut s = System::new();
                // First check what happens in case the process isn't already in our process list.
                assert!(s.refresh_process(_pid));
                // Then check that it still returns true if the process is already in our process list.
                assert!(s.refresh_process(_pid));
            }
        }
    }

    #[test]
    fn ensure_is_supported_is_set_correctly() {
        if MIN_USERS > 0 {
            assert!(System::IS_SUPPORTED);
        } else {
            assert!(!System::IS_SUPPORTED);
        }
    }

    #[test]
    fn check_processors_number() {
        let s = System::new();

        if System::IS_SUPPORTED {
            assert!(!s.processors().is_empty());
            // In case we are running inside a VM, it's possible to not have a physical core, only
            // logical ones, which is why we don't test `physical_cores_count > 0`.
            let physical_cores_count = s
                .physical_core_count()
                .expect("failed to get number of physical cores");
            assert!(physical_cores_count <= s.processors().len());
        } else {
            assert!(s.processors().is_empty());
            assert_eq!(s.physical_core_count(), None);
        }
        assert!(s.physical_core_count().unwrap_or(0) <= s.processors().len());
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
/// ```
/// fn is_send<T: Send>() {}
/// is_send::<sysinfo::System>();
/// ```
///
/// ```
/// fn is_sync<T: Sync>() {}
/// is_sync::<sysinfo::System>();
/// ```
pub mod check_if_system_is_send_and_sync {}
<commit_msg>Remove (very) old attributes<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

#![doc = include_str!("../README.md")]
#![allow(unknown_lints)]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]
#![allow(unknown_lints)]

#[cfg(feature = "debug")]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
#[allow(unused)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(feature = "unknown-ci")] {
        // This is used in CI to check that the build for unknown targets is compiling fine.
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        pub(crate) const MIN_USERS: usize = 0;
    }
}

pub use common::{
    get_current_pid, AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, ProcessStatus,
    RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    cfg_if::cfg_if! {
        if #[cfg(all(not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
        {
            if _new_limit < 0 {
                _new_limit = 0;
            }
            let max = sys::system::get_max_nb_fds();
            if _new_limit > max {
                _new_limit = max;
            }
            if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
                // If files are already open, to be sure that the number won't be bigger when those
                // files are closed, we subtract the current number of opened files to the new
                // limit.
                let diff = max - **x;
                **x = _new_limit - diff;
                true
            } else {
                false
            }
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use crate::*;

    #[cfg(feature = "unknown-ci")]
    #[test]
    fn check_unknown_ci_feature() {
        assert!(!System::IS_SUPPORTED);
    }

    #[test]
    fn check_process_memory_usage() {
        let mut s = System::new();
        s.refresh_all();

        if System::IS_SUPPORTED {
            // No process should have 0 as memory usage.
            #[cfg(not(feature = "apple-sandbox"))]
            assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        } else {
            // There should be no process, but if there is one, its memory usage should be 0.
            assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
        }
    }

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        assert_eq!(s.total_memory(), 0);
        assert_eq!(s.free_memory(), 0);
        assert_eq!(s.available_memory(), 0);
        assert_eq!(s.used_memory(), 0);
        assert_eq!(s.total_swap(), 0);
        assert_eq!(s.free_swap(), 0);
        assert_eq!(s.used_swap(), 0);

        s.refresh_memory();
        if System::IS_SUPPORTED {
            assert!(s.total_memory() > 0);
            assert!(s.used_memory() > 0);
            if s.total_swap() > 0 {
                // I think it's pretty safe to assume that there is still some swap left...
                assert!(s.free_swap() > 0);
            }
        } else {
            assert_eq!(s.total_memory(), 0);
            assert_eq!(s.used_memory(), 0);
            assert_eq!(s.total_swap(), 0);
            assert_eq!(s.free_swap(), 0);
        }
    }

    #[cfg(target_os = "linux")]
    #[test]
    fn check_processes_cpu_usage() {
        if !System::IS_SUPPORTED {
            return;
        }
        let mut s = System::new();

        s.refresh_processes();
        // All CPU usage will start at zero until the second refresh
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() == 0.0));

        // Wait a bit to update CPU usage values
        std::thread::sleep(std::time::Duration::from_millis(100));
        s.refresh_processes();
        assert!(s
            .processes()
            .iter()
            .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
                && proc_.cpu_usage() <= (s.processors().len() as f32) * 100.0));
        assert!(s
            .processes()
            .iter()
            .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        assert!(s.users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_all();
        assert!(s.users().is_empty());

        let s = System::new_all();
        assert!(s.users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.users().is_empty());
        s.refresh_users_list();
        let users = s.users();
        assert!(users.len() >= MIN_USERS);

        if System::IS_SUPPORTED {
            #[cfg(not(target_os = "windows"))]
            {
                let user = users
                    .iter()
                    .find(|u| u.name() == "root")
                    .expect("no root user");
                assert_eq!(*user.uid(), 0);
                assert_eq!(*user.gid(), 0);
                if let Some(user) = users.iter().find(|u| *u.gid() > 0) {
                    assert!(*user.uid() > 0);
                    assert!(*user.gid() > 0);
                }
            }
            #[cfg(not(target_os = "windows"))]
            {
                assert!(users.iter().filter(|u| *u.uid() > 0).count() > 0);
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.name().expect("Failed to get system name").is_empty());

            assert!(!s
                .kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s.os_version().expect("Failed to get os version").is_empty());

            assert!(!s
                .long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let s = System::new();
            assert!(!s.host_name().expect("Failed to get host name").is_empty());
        }
    }

    #[test]
    fn check_refresh_process_return_value() {
        // We don't want to test on unsupported systems.
        if System::IS_SUPPORTED {
            let _pid = get_current_pid().expect("Failed to get current PID");

            #[cfg(not(feature = "apple-sandbox"))]
            {
                let mut s = System::new();
                // First check what happens in case the process isn't already in our process list.
                assert!(s.refresh_process(_pid));
                // Then check that it still returns true if the process is already in our process list.
                assert!(s.refresh_process(_pid));
            }
        }
    }

    #[test]
    fn ensure_is_supported_is_set_correctly() {
        if MIN_USERS > 0 {
            assert!(System::IS_SUPPORTED);
        } else {
            assert!(!System::IS_SUPPORTED);
        }
    }

    #[test]
    fn check_processors_number() {
        let s = System::new();

        if System::IS_SUPPORTED {
            assert!(!s.processors().is_empty());
            // In case we are running inside a VM, it's possible to not have a physical core, only
            // logical ones, which is why we don't test `physical_cores_count > 0`.
            let physical_cores_count = s
                .physical_core_count()
                .expect("failed to get number of physical cores");
            assert!(physical_cores_count <= s.processors().len());
        } else {
            assert!(s.processors().is_empty());
            assert_eq!(s.physical_core_count(), None);
        }
        assert!(s.physical_core_count().unwrap_or(0) <= s.processors().len());
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
/// ```
/// fn is_send<T: Send>() {}
/// is_send::<sysinfo::System>();
/// ```
///
/// ```
/// fn is_sync<T: Sync>() {}
/// is_sync::<sysinfo::System>();
/// ```
pub mod check_if_system_is_send_and_sync {}
<|endoftext|>


<commit_before>#![crate_name = "compress"]
#![deny(missing_docs, warnings)]
#![feature(macro_rules, phase)]

//! dox (placeholder)

#[phase(plugin, link)]
extern crate log;

#[cfg(test)] extern crate rand;
#[cfg(test)] extern crate test;

/// Public exports
#[cfg(feature="checksum")]
pub use self::checksum::adler::State32 as Adler32;

#[cfg(feature="checksum")]
/// Checksum algorithms. Requires `checksum` feature, enabled by default
// http://en.wikipedia.org/wiki/Checksum
pub mod checksum {
    pub mod adler;
}

#[cfg(feature="bwt")]
pub mod bwt;

#[cfg(feature="flate")]
pub mod flate;

#[cfg(feature="lz4")]
pub mod lz4;

#[cfg(feature="zlib")]
pub mod zlib;

/// Entropy coder family. Requires `entropy` feature, enabled by default
// http://en.wikipedia.org/wiki/Entropy_encoding
#[cfg(feature="entropy")]
pub mod entropy {
    pub mod ari;
}
<commit_msg>Opt out copy because of bwt iterators problem<commit_after>#![crate_name = "compress"]
#![deny(missing_docs, warnings)]
#![feature(macro_rules, phase, opt_out_copy)]

//! dox (placeholder)

#[phase(plugin, link)]
extern crate log;

#[cfg(test)] extern crate rand;
#[cfg(test)] extern crate test;

/// Public exports
#[cfg(feature="checksum")]
pub use self::checksum::adler::State32 as Adler32;

#[cfg(feature="checksum")]
/// Checksum algorithms. Requires `checksum` feature, enabled by default
// http://en.wikipedia.org/wiki/Checksum
pub mod checksum {
    pub mod adler;
}

#[cfg(feature="bwt")]
pub mod bwt;

#[cfg(feature="flate")]
pub mod flate;

#[cfg(feature="lz4")]
pub mod lz4;

#[cfg(feature="zlib")]
pub mod zlib;

/// Entropy coder family. Requires `entropy` feature, enabled by default
// http://en.wikipedia.org/wiki/Entropy_encoding
#[cfg(feature="entropy")]
pub mod entropy {
    pub mod ari;
}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin, const_fn, type_ascription)]
#![plugin(serde_macros)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications,
        warnings)]

//! Implementation of the build engine. This contains entry points and some misc utils for launchers.

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

extern crate bincode;
extern crate byteorder;
extern crate either;
extern crate env_logger;
extern crate hlua;
extern crate mio;
extern crate serde;
extern crate slab;

pub mod net;
pub mod script;

use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::error::Error;
use std::fmt::{Display, Error as FmtError, Formatter};
use std::io;
use std::net::SocketAddr;

use mio::tcp::TcpListener;

use net::{EventLoop, EventLoopImpl, MAX_CONNECTIONS, client};
use net::client::Client;

/// The current version of buildengine. Fallows Semantic Versioning.
pub const VERSION: &'static str = "0.0.1";

/// If the game is allowed to crash in the event of a semi-handleable error, such as a bad network packet or a peer crashing.
///
/// Programming mistakes however, will still panic.
static SHOULD_CRASH: AtomicBool = AtomicBool::new(true);    // Basically Erlang's too_big_to_fail process_flag.

/// Main game struct. Contains all state nescary to work.
///
/// While you may never need the fields exposed, they are exposed if you ever want to inspect the game state.
/// You probably, however don't want to mutate the state directly. That can mess up client-server syncronization.
#[derive(Debug)]
pub struct Engine<'be> {
    /// The clientside or serverside networking state.
    ///
    /// Currently a Some if it is a client, or None if server.
    pub net_state: Option<Client>,

    /// The networking event loop. Mostly used in other functions for sending, adding, and killing connections.
    ///
    /// Also contains all state relating to networking.
    pub event_loop: Box<EventLoop>,

    /// The scripting backend for the engine.
    ///
    /// Not present on a client, for security reasons.
    pub script_engine: Option<script::Engine<'be>>,
}

impl<'be> Engine<'be> {
    /// Creates a new client game.
    pub fn new_client(server_address: SocketAddr) -> Result<Self, InitError> {
        let mut event_loop = try!(EventLoopImpl::new(MAX_CONNECTIONS, Vec::new()));
        let client = try!(Client::spawn_client(server_address, &mut event_loop));
        Ok(Engine {
            event_loop: Box::new(event_loop),
            net_state: Some(client),
            script_engine: None,
        })
    }

    /// Creates a new server.
    pub fn new_server(server_address: &SocketAddr, game_scripts: HashMap<String, String>) -> Result<Self, InitError> {
        let event_loop = try!(EventLoopImpl::new(MAX_CONNECTIONS, Vec::new()));
        let listener = try!(TcpListener::bind(server_address));
        event_loop.add_listener(listener);
        Ok(Engine {
            event_loop: Box::new(event_loop),
            net_state: None,
            script_engine: Some(script::Engine::new(game_scripts)),
        })
    }
}

/// An error hapened while initing the game.
#[derive(Debug)]
pub enum InitError {
    /// An error occoured when initalising the client code.
    ClientInitError(client::InitError),
    /// An std::io::Error. Who knows where this comes up.
    IoError(io::Error),
}

impl Display for InitError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match *self {
            InitError::ClientInitError(ref err) => write!(fmt, "ClientInitError: {}", err),
            InitError::IoError(ref err) => write!(fmt, "IoError: {}", err),
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::ClientInitError(ref err) => err.description(),
            InitError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            InitError::ClientInitError(ref err) => Some(err),
            InitError::IoError(ref err) => Some(err),
        }
    }
}

impl From<client::InitError> for InitError {
    fn from(err: client::InitError) -> Self {
        InitError::ClientInitError(err)
    }
}

impl From<io::Error> for InitError {
    fn from(err: io::Error) -> Self {
        InitError::IoError(err)
    }
}

/// Initalizes the global parts of the engine.
///
/// Currently it only inits the logger, but later may do other things.
///
/// #Panics
/// * Calling the function once it has already been called.
pub fn global_init() {
    env_logger::init().expect("Already inited the logging server!");
}

/// Prints "Hello World!" to stdout. Will be removed in future versions.
pub fn print_hello_world() {
    println!("Hello World!");
}

fn check_should_crash() -> bool {
    SHOULD_CRASH.load(Ordering::Relaxed)
}
<commit_msg>Remove unneeded feature flag<commit_after>#![feature(custom_derive, plugin, const_fn)]
#![plugin(serde_macros)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications,
        warnings)]

//! Implementation of the build engine. This contains entry points and some misc utils for launchers.

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

extern crate bincode;
extern crate byteorder;
extern crate either;
extern crate env_logger;
extern crate hlua;
extern crate mio;
extern crate serde;
extern crate slab;

pub mod net;
pub mod script;

use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::error::Error;
use std::fmt::{Display, Error as FmtError, Formatter};
use std::io;
use std::net::SocketAddr;

use mio::tcp::TcpListener;

use net::{EventLoop, EventLoopImpl, MAX_CONNECTIONS, client};
use net::client::Client;

/// The current version of buildengine. Fallows Semantic Versioning.
pub const VERSION: &'static str = "0.0.1";

/// If the game is allowed to crash in the event of a semi-handleable error, such as a bad network packet or a peer crashing.
///
/// Programming mistakes however, will still panic.
static SHOULD_CRASH: AtomicBool = AtomicBool::new(true);    // Basically Erlang's too_big_to_fail process_flag.

/// Main game struct. Contains all state nescary to work.
///
/// While you may never need the fields exposed, they are exposed if you ever want to inspect the game state.
/// You probably, however don't want to mutate the state directly. That can mess up client-server syncronization.
#[derive(Debug)]
pub struct Engine<'be> {
    /// The clientside or serverside networking state.
    ///
    /// Currently a Some if it is a client, or None if server.
    pub net_state: Option<Client>,

    /// The networking event loop. Mostly used in other functions for sending, adding, and killing connections.
    ///
    /// Also contains all state relating to networking.
    pub event_loop: Box<EventLoop>,

    /// The scripting backend for the engine.
    ///
    /// Not present on a client, for security reasons.
    pub script_engine: Option<script::Engine<'be>>,
}

impl<'be> Engine<'be> {
    /// Creates a new client game.
    pub fn new_client(server_address: SocketAddr) -> Result<Self, InitError> {
        let mut event_loop = try!(EventLoopImpl::new(MAX_CONNECTIONS, Vec::new()));
        let client = try!(Client::spawn_client(server_address, &mut event_loop));
        Ok(Engine {
            event_loop: Box::new(event_loop),
            net_state: Some(client),
            script_engine: None,
        })
    }

    /// Creates a new server.
    pub fn new_server(server_address: &SocketAddr,
                      game_scripts: HashMap<String, String>)
                      -> Result<Self, InitError> {
        let event_loop = try!(EventLoopImpl::new(MAX_CONNECTIONS, Vec::new()));
        let listener = try!(TcpListener::bind(server_address));
        event_loop.add_listener(listener);
        Ok(Engine {
            event_loop: Box::new(event_loop),
            net_state: None,
            script_engine: Some(script::Engine::new(game_scripts)),
        })
    }
}

/// An error hapened while initing the game.
#[derive(Debug)]
pub enum InitError {
    /// An error occoured when initalising the client code.
    ClientInitError(client::InitError),
    /// An std::io::Error. Who knows where this comes up.
    IoError(io::Error),
}

impl Display for InitError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match *self {
            InitError::ClientInitError(ref err) => write!(fmt, "ClientInitError: {}", err),
            InitError::IoError(ref err) => write!(fmt, "IoError: {}", err),
        }
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::ClientInitError(ref err) => err.description(),
            InitError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            InitError::ClientInitError(ref err) => Some(err),
            InitError::IoError(ref err) => Some(err),
        }
    }
}

impl From<client::InitError> for InitError {
    fn from(err: client::InitError) -> Self {
        InitError::ClientInitError(err)
    }
}

impl From<io::Error> for InitError {
    fn from(err: io::Error) -> Self {
        InitError::IoError(err)
    }
}

/// Initalizes the global parts of the engine.
///
/// Currently it only inits the logger, but later may do other things.
///
/// #Panics
/// * Calling the function once it has already been called.
pub fn global_init() {
    env_logger::init().expect("Already inited the logging server!");
}

/// Prints "Hello World!" to stdout. Will be removed in future versions.
pub fn print_hello_world() {
    println!("Hello World!");
}

fn check_should_crash() -> bool {
    SHOULD_CRASH.load(Ordering::Relaxed)
}
<|endoftext|>


<commit_before>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!
//!     println!("test 0");
//!     print!("{}", set_column(1));
//!     println!("test 1");
//!     print!("{}", clear_display(Pos::Both));
//!

use std::cmp::{self, Ordering};

/// A Pos is position of clearing (display|line) from cursor.
pub enum Pos {
    Back,
    Front,
    Both,
}

impl Pos {
    fn num(&self) -> u32 {
        match *self {
            Pos::Back   => 0,
            Pos::Front  => 1,
            Pos::Both   => 2,
        }
    }
}

/// Moves the cursor _i_ (row), _j_ (column) cells. If the cursor
/// is already at the edge of the screen, this has no effect.
pub fn move_cursor(i: i32, j: i32) -> String {
    let code0 = match i.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}B", -i),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}A", i),
    };
    let code1 = match j.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}D", -j),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}C", j),
    };
    format!("{}{}", code0, code1)
}

/// Moves the cursor to beginning of the line _n_ lines down.
/// If _n_ is a negative number, this function moves the cursor
/// _|n|_ lines up.
pub fn move_line(n: i32) -> String {
    match n.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}F", -n),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}E", n),
    }
}

/// Sets the column of the cursor. (n: column)
pub fn set_column(n: u32) -> String {
    format!("\x1B[{}G", cmp::max(1, n))
}

/// Sets the position of the cursor. (i: row, j: column)
pub fn set_position(i: u32, j: u32) -> String {
    format!("\x1B[{};{}H", cmp::max(1, i), cmp::max(1, j))
}

/// Clears part of screen. If pos is Pos::Back, clear from cursor
/// to the end of the screen. If pos is Pos::Front, clear from
/// cursor to beginning of the screen. If pos is Pos::Both, clear
/// entire screen.
pub fn clear_display(pos: Pos) -> String {
    format!("\x1B[{}J", pos.num())
}

/// Clears part of line. If pos is Pos::Back, clear from cursor
/// to the end of the line. If pos is Pos::Front, clear from
/// cursor to beginning of the line. If pos is Pos::Both, clear
/// entire line.
pub fn clear_line(pos: Pos) -> String {
    format!("\x1B[{}K", pos.num())
}

/// Scroll whole page up by _n_ lines. If _n_ is a negative
/// number, this function scroll whole page down by _|n|_ lines.
pub fn scroll(n: i32) -> String {
    match n.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}T", -n),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}S", n),
    }
}

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<commit_msg>Improve descriptions<commit_after>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!
//!     println!("test 0");
//!     print!("{}", set_column(1));
//!     println!("test 1");
//!     print!("{}", clear_display(Pos::Both));
//!

use std::cmp::{self, Ordering};

/// A Pos is position of clearing (display|line) from cursor.
pub enum Pos {
    Back,
    Front,
    Both,
}

impl Pos {
    fn num(&self) -> u32 {
        match *self {
            Pos::Back   => 0,
            Pos::Front  => 1,
            Pos::Both   => 2,
        }
    }
}

/// Moves the cursor _i_ (row), _j_ (column) cells. If the cursor
/// is already at the edge of the screen, this has no effect.
pub fn move_cursor(i: i32, j: i32) -> String {
    let code0 = match i.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}B", -i),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}A", i),
    };
    let code1 = match j.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}D", -j),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}C", j),
    };
    format!("{}{}", code0, code1)
}

/// Moves the cursor to beginning of the line _n_ lines down.
/// If _n_ is a negative number, this function moves the cursor
/// _|n|_ lines up.
pub fn move_line(n: i32) -> String {
    match n.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}F", -n),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}E", n),
    }
}

/// Sets the column of the cursor. (_n_: column)
pub fn set_column(n: u32) -> String {
    format!("\x1B[{}G", cmp::max(1, n))
}

/// Sets the position of the cursor. (_i_: row, _j_: column)
pub fn set_position(i: u32, j: u32) -> String {
    format!("\x1B[{};{}H", cmp::max(1, i), cmp::max(1, j))
}

/// Clears part of screen. If pos is Pos::Back, clear from cursor
/// to the end of the screen. If pos is Pos::Front, clear from
/// cursor to beginning of the screen. If pos is Pos::Both, clear
/// entire screen.
pub fn clear_display(pos: Pos) -> String {
    format!("\x1B[{}J", pos.num())
}

/// Clears part of line. If pos is Pos::Back, clear from cursor
/// to the end of the line. If pos is Pos::Front, clear from
/// cursor to beginning of the line. If pos is Pos::Both, clear
/// entire line.
pub fn clear_line(pos: Pos) -> String {
    format!("\x1B[{}K", pos.num())
}

/// Scroll whole page up by _n_ lines. If _n_ is a negative
/// number, this function scroll whole page down by _|n|_ lines.
pub fn scroll(n: i32) -> String {
    match n.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}T", -n),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}S", n),
    }
}

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "currency"]

extern crate regex;

use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::cmp::Ordering;

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;

use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

use std::marker::Copy;

/// Represents currency through an optional symbol and amount of coin.
///
/// Each 100 coins results in a banknote. (100 is formatted as 1.00)
/// The currency will be formatted as such:
///     Currency(Some('$'), 432) ==> "$4.32"
#[derive(Debug)]
pub struct Currency(pub Option<char>, pub i64);

impl Currency {
    /// Creates a blank Currency as Currency(None, 0)
    ///
    /// # Examples
    /// ```
	/// use currency::Currency;
	///
    /// let mut c = Currency::new();
    /// ```
    #[inline]
    #[allow(dead_code)]
    pub fn new() -> Currency {
        Currency(None, 0)
    }

    /// Uses a Regular Expression to parse a string literal (&str) and turns it into a currency.
    ///
    /// This Can recognize European style (€1,00)
	/// The display method will print out the format as $1000.00 (no comma delimiting, with decimal)
    ///
    /// # Examples
    /// ```
	/// use currency::Currency;
	///
    /// assert!(Currency::from_string("$4.32") == Currency(Some('$'), 432));
    /// assert!(Currency::from_string("424.44") == Currency(None, 42444));
    /// assert!(Currency::from_string("¥12") == Currency(Some('¥'), 1200));
	/// assert!(Currency::from_string("£12,00") == Currency(Some('£'), 1200));
    /// ```
    ///
    /// # Failures
    /// Fails if the string is not formatted correctly
    ///
    /// # Panics
    /// Panics if a number fails to be parsed; this only occurs if the string
    /// argument has no numbers in it.
    #[allow(dead_code)]
    pub fn from_string(s: &str) -> Currency {
		use regex::Regex;

		let s = s.trim();
		let re = Regex::new(r"(?:\b|(\p{Sc})?)((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b").unwrap();

		if !re.is_match(s) {
			panic!("Failed to convert \"{}\" to currency", s);
		}

		let mut sign: Option<char> = None;
		let mut coin_str: String = "".to_string();

		// If anyone's looking at this and knows how to do this without a loop, fork this.
		for cap in re.captures_iter(s) {
			// Without this, there is undefined behavior (try putting a character in the middle of s)
			if cap.at(0).unwrap_or("") != s {
				panic!("Failed to convert \"{}\" to currency", s);
			}

			if cap.at(1).is_some() {
				sign = Some(s.chars().next().unwrap());
			}
			coin_str = cap.at(2).unwrap().replace(".", "").replace(",", "") + cap.at(3).unwrap_or("00");

			break;
		}

		let coin: i64 = coin_str.parse::<i64>().ok().unwrap();

		Currency(sign, coin)
	}
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialEq<Currency> for Currency {
    #[inline]
    fn eq(&self, rhs: &Currency) -> bool {
        self.0 == rhs.0 && self.1 == rhs.1
    }

    #[inline]
    fn ne(&self, rhs: &Currency) -> bool {
        self.0 != rhs.0 || self.1 != rhs.1
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    #[inline]
    fn partial_cmp(&self, rhs: &Currency) -> Option<Ordering> {
        if self.0 == rhs.0 {
            if self < rhs { return Some(Ordering::Less) }
            if self == rhs { return Some(Ordering::Equal) }
            if self > rhs { return Some(Ordering::Greater) }
        }
        None
    }

    #[inline]
    fn lt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 < rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn le(&self, rhs: &Currency) -> bool {
        self < rhs || self == rhs
    }
    #[inline]
    fn gt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 > rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn ge(&self, rhs: &Currency) -> bool {
        self > rhs || self == rhs
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the
/// Currency's symbol.
impl Add for Currency {
    type Output = Currency;

    #[inline]
    fn add(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 + rhs.1)
        } else {
            panic!("Cannot add two different types of currency!");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency,
/// as denoted by the Currency's symbol.
impl Sub for Currency {
    type Output = Currency;

    #[inline]
    fn sub(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 - rhs.1)
        } else {
            panic!("Cannot subtract two different types of currency!");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl Mul<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 * rhs)
    }
}

/// Overloads the '*' operator for i64.
///
/// Allows an i64 to be multiplied by a Currency.
/// Completes the commutative property for i64 multiplied by Currency.
impl Mul<Currency> for i64 {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: Currency) -> Currency {
        Currency(rhs.0, rhs.1 * self)
    }
}

/// Overloads the '/' operator for Currency objects.
///
/// Allows a Currency to be divided by an i64.
impl Div<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn div(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 / rhs)
    }
}

/// Allows Currencies to be displayed as Strings
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
/// assert!(Currency(None, 1210).to_string() == "12.10");
/// ```
impl Display for Currency {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
        let decimal = (self.1 / 100).to_string()
            + &('.').to_string()
            + &(self.1 % 100).to_string();
        match self.0 {
            Some(c) => write!(f, "{}{}", c, decimal),
            None    => write!(f, "{}", decimal),
        }
    }
}

/// Allows Currencies to be copied, rather than using move semantics.
impl Copy for Currency { }
impl Clone for Currency {
    #[inline]
    fn clone(&self) -> Currency { *self }
}

<commit_msg>formatting is much better. add different formats<commit_after>#![crate_type = "lib"]
#![crate_name = "currency"]

extern crate regex;

use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::cmp::Ordering;

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;

use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;

use std::marker::Copy;

/// Represents currency through an optional symbol and amount of coin.
///
/// Each 100 coins results in a banknote. (100 is formatted as 1.00)
/// The currency will be formatted as such:
///     Currency(Some('$'), 432) ==> "$4.32"
#[derive(Debug)]
pub struct Currency(pub Option<char>, pub i64);

impl Currency {
    /// Creates a blank Currency as Currency(None, 0)
    ///
    /// # Examples
    /// ```
	/// use currency::Currency;
	///
    /// let mut c = Currency::new();
    /// ```
    #[inline]
    #[allow(dead_code)]
    pub fn new() -> Currency {
        Currency(None, 0)
    }

    /// Uses a Regular Expression to parse a string literal (&str) and turns it into a currency.
    ///
    /// The Regex recognizes European notation (€1,00)
	/// The display method will print out the format with no comma delimiting with decimal($1000.00)
    ///
    /// # Examples
    /// ```
	/// use currency::Currency;
	///
    /// assert!(Currency::from_string("$4.32") == Currency(Some('$'), 432));
    /// assert!(Currency::from_string("424.44") == Currency(None, 42444));
	/// assert!(Currency::from_string("£12,00") == Currency(Some('£'), 1200));
	/// assert!(Currency::from_string("¥12") == Currency(Some('¥'), 1200));
    /// ```
    ///
    /// # Failures
    /// Fails if the string is not formatted correctly.
	/// Fails to parse negative money.
    ///
    /// # Panics
    /// Panics if a number fails to be parsed; this only occurs if the string
    /// argument has no numbers in it.
    #[allow(dead_code)]
    pub fn from_string(s: &str) -> Currency {
		use regex::Regex;

		// Shadow s with a trimmed version
		let s = s.trim();
		let re = Regex::new(r"(?:\b|(\p{Sc})?)((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b").unwrap();

		if !re.is_match(s) {
			panic!("Failed to convert \"{}\" to currency", s);
		}

		let mut sign: Option<char> = None;
		let mut coin_str: String = "".to_string();

		// If anyone's looking at this and knows how to do this without a loop, fork this.
		for cap in re.captures_iter(s) {
			// Without this, there is undefined behavior (try putting a character in the middle of s)
			if cap.at(0).unwrap_or("") != s {
				panic!("Failed to convert \"{}\" to currency", s);
			}

			if cap.at(1).is_some() {
				sign = Some(s.chars().next().unwrap());
			}
			coin_str = cap.at(2).unwrap().replace(".", "").replace(",", "") + cap.at(3).unwrap_or("00");

			break;
		}

		let coin: i64 = coin_str.parse::<i64>().ok().unwrap();

		Currency(sign, coin)
	}
}

/// Allows Currencies to be displayed as Strings
/// println!("{}", Currency(Some('$'), 1099)) -> "$10.99"
///
/// # Examples
/// ```
/// use currency::Currency;
///
/// assert!(Currency(Some('$'), 1210).to_string() == "$12.10");
/// assert!(Currency(None, 1210).to_string() == "12.10");
/// ```
impl Display for Currency {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result {
		let decimal = format!("{:.*}", 2, (self.1 as f32 / 100.0));
        match self.0 {
            Some(c) => write!(f, "{}{}", c, decimal),
            None    => write!(f, "{}", decimal),
        }
    }
}

/// Overloads the '==' operator for Currency objects.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialEq<Currency> for Currency {
    #[inline]
    fn eq(&self, rhs: &Currency) -> bool {
        self.0 == rhs.0 && self.1 == rhs.1
    }

    #[inline]
    fn ne(&self, rhs: &Currency) -> bool {
        self.0 != rhs.0 || self.1 != rhs.1
    }
}

/// Overloads the order operators for Currency objects.
///
/// These operators include '<', '<=', '>', and '>='.
///
/// # Panics
/// Panics if the two comparators are different types of currency, as denoted by
/// the Currency's symbol.
impl PartialOrd<Currency> for Currency {
    #[inline]
    fn partial_cmp(&self, rhs: &Currency) -> Option<Ordering> {
        if self.0 == rhs.0 {
            if self < rhs { return Some(Ordering::Less) }
            if self == rhs { return Some(Ordering::Equal) }
            if self > rhs { return Some(Ordering::Greater) }
        }
        None
    }

    #[inline]
    fn lt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 < rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn le(&self, rhs: &Currency) -> bool {
        self < rhs || self == rhs
    }
    #[inline]
    fn gt(&self, rhs: &Currency) -> bool {
        if self.0 == rhs.0 {
            self.1 > rhs.1
        }
        else {
            panic!("Cannot compare two different types of currency.");
        }
    }
    #[inline]
    fn ge(&self, rhs: &Currency) -> bool {
        self > rhs || self == rhs
    }
}

/// Overloads the '+' operator for Currency objects.
///
/// # Panics
/// Panics if the two addends are different types of currency, as denoted by the
/// Currency's symbol.
impl Add for Currency {
    type Output = Currency;

    #[inline]
    fn add(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 + rhs.1)
        } else {
            panic!("Cannot add two different types of currency!");
        }
    }
}

/// Overloads the '-' operator for Currency objects.
///
/// # Panics
/// Panics if the minuend and subtrahend are two different types of currency,
/// as denoted by the Currency's symbol.
impl Sub for Currency {
    type Output = Currency;

    #[inline]
    fn sub(self, rhs: Currency) -> Currency {
        if self.0 == rhs.0 {
            Currency(self.0, self.1 - rhs.1)
        } else {
            panic!("Cannot subtract two different types of currency!");
        }
    }
}

/// Overloads the '*' operator for Currency objects.
///
/// Allows a Currency to be multiplied by an i64.
impl Mul<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 * rhs)
    }
}

/// Overloads the '*' operator for i64.
///
/// Allows an i64 to be multiplied by a Currency.
/// Completes the commutative property for i64 multiplied by Currency.
impl Mul<Currency> for i64 {
    type Output = Currency;

    #[inline]
    fn mul(self, rhs: Currency) -> Currency {
        Currency(rhs.0, rhs.1 * self)
    }
}

/// Overloads the '/' operator for Currency objects.
///
/// Allows a Currency to be divided by an i64.
impl Div<i64> for Currency {
    type Output = Currency;

    #[inline]
    fn div(self, rhs: i64) -> Currency {
        Currency(self.0, self.1 / rhs)
    }
}

/// Allows Currencies to be copied, rather than using move semantics.
impl Copy for Currency { }
impl Clone for Currency {
    #[inline]
    fn clone(&self) -> Currency { *self }
}

<|endoftext|>