<commit_before>// Copyright 2013 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.

//! A cache that holds a limited number of key-value pairs. When the
//! capacity of the cache is exceeded, the least-recently-used
//! (where "used" means a look-up or putting the pair into the cache)
//! pair is automatically removed.
//!
//! # Examples
//!
//! ```
//! # extern crate "lru-cache" as lru_cache;
//! # fn main() {
//! use lru_cache::LruCache;
//!
//! let mut cache = LruCache::new(2);
//!
//! cache.insert(1, 10);
//! cache.insert(2, 20);
//! cache.insert(3, 30);
//! assert!(cache.get(&1).is_none());
//! assert_eq!(*cache.get(&2).unwrap(), 20);
//! assert_eq!(*cache.get(&3).unwrap(), 30);
//!
//! cache.insert(2, 22);
//! assert_eq!(*cache.get(&2).unwrap(), 22);
//!
//! cache.insert(6, 60);
//! assert!(cache.get(&3).is_none());
//!
//! cache.set_capacity(1);
//! assert!(cache.get(&2).is_none());
//! # }
//! ```

extern crate "linked-hash-map" as linked_hash_map;

use std::fmt;
use std::hash::Hash;
use std::iter::{IntoIterator, Extend};

use linked_hash_map::LinkedHashMap;

// FIXME(conventions): implement iterators?
// FIXME(conventions): implement indexing?

/// An LRU cache.
#[derive(Clone)]
pub struct LruCache<K, V> where K: Eq + Hash {
    map: LinkedHashMap<K, V>,
    max_size: usize,
}

impl<K: Hash + Eq, V> LruCache<K, V> {
    /// Creates an empty cache that can hold at most `capacity` items.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(10);
    /// # }
    /// ```
    pub fn new(capacity: usize) -> LruCache<K, V> {
        LruCache {
            map: LinkedHashMap::new(),
            max_size: capacity,
        }
    }

    /// Inserts a key-value pair into the cache. If the key already existed, the old value is
    /// returned.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// # }
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        let old_val = self.map.insert(k, v);
        if self.len() > self.capacity() {
            self.remove_lru();
        }
        old_val
    }

    /// Returns the value corresponding to the given key in the cache.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(2, "c");
    /// cache.insert(3, "d");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"c"));
    /// # }
    /// ```
    pub fn get(&mut self, k: &K) -> Option<&V> {
        self.map.get_refresh(k)
    }

    /// Removes the given key from the cache and returns its corresponding value.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(2, "a");
    ///
    /// assert_eq!(cache.remove(&1), None);
    /// assert_eq!(cache.remove(&2), Some("a"));
    /// assert_eq!(cache.remove(&2), None);
    /// assert_eq!(cache.len(), 0);
    /// # }
    /// ```
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Returns the maximum number of key-value pairs the cache can hold.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(2);
    /// assert_eq!(cache.capacity(), 2);
    /// # }
    /// ```
    pub fn capacity(&self) -> usize {
        self.max_size
    }

    /// Sets the number of key-value pairs the cache can hold. Removes
    /// least-recently-used key-value pairs if necessary.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(3, "c");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(3);
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    ///
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(1);
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), None);
    /// assert_eq!(cache.get(&3), Some(&"c"));
    /// # }
    /// ```
    pub fn set_capacity(&mut self, capacity: usize) {
        for _ in capacity..self.len() {
            self.remove_lru();
        }
        self.max_size = capacity;
    }

    #[inline]
    fn remove_lru(&mut self) {
        self.map.pop_front()
    }

    /// Returns the number of key-value pairs in the cache.
    pub fn len(&self) -> usize { self.map.len() }

    /// Returns `true` if the cache contains no key-value pairs.
    pub fn is_empty(&self) -> bool { self.map.is_empty() }

    /// Removes all key-value pairs from the cache.
    pub fn clear(&mut self) { self.map.clear(); }

}

impl<K: Hash + Eq, V> Extend<(K, V)> for LruCache<K, V> {
    fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl<A: fmt::Debug + Hash + Eq, B: fmt::Debug> fmt::Debug for LruCache<A, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{{"));

        for (i, (k, v)) in self.map.iter().rev().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}: {:?}", *k, *v));
        }

        write!(f, "}}")
    }
}

unsafe impl<K: Send, V: Send> Send for LruCache<K, V> {}

unsafe impl<K: Sync, V: Sync> Sync for LruCache<K, V> {}

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

    fn assert_opt_eq<V: PartialEq>(opt: Option<&V>, v: V) {
        assert!(opt.is_some());
        assert!(opt.unwrap() == &v);
    }

    #[test]
    fn test_put_and_get() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_opt_eq(cache.get(&1), 10);
        assert_opt_eq(cache.get(&2), 20);
        assert_eq!(cache.len(), 2);
    }

    #[test]
    fn test_put_update() {
        let mut cache: LruCache<String, Vec<u8>> = LruCache::new(1);
        cache.insert("1".to_string(), vec![10, 10]);
        cache.insert("1".to_string(), vec![10, 19]);
        assert_opt_eq(cache.get(&"1".to_string()), vec![10, 19]);
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_expire_lru() {
        let mut cache: LruCache<String, String> = LruCache::new(2);
        cache.insert("foo1".to_string(), "bar1".to_string());
        cache.insert("foo2".to_string(), "bar2".to_string());
        cache.insert("foo3".to_string(), "bar3".to_string());
        assert!(cache.get(&"foo1".to_string()).is_none());
        cache.insert("foo2".to_string(), "bar2update".to_string());
        cache.insert("foo4".to_string(), "bar4".to_string());
        assert!(cache.get(&"foo3".to_string()).is_none());
    }

    #[test]
    fn test_pop() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_eq!(cache.len(), 2);
        let opt1 = cache.remove(&1);
        assert!(opt1.is_some());
        assert_eq!(opt1.unwrap(), 10);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_change_capacity() {
        let mut cache = LruCache::new(2);
        assert_eq!(cache.capacity(), 2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.set_capacity(1);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.capacity(), 1);
    }

    #[test]
    fn test_debug() {
        let mut cache: LruCache<i32, i32> = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        assert_eq!(format!("{:?}", cache), "{3: 30, 2: 20, 1: 10}");
        cache.insert(2, 22);
        assert_eq!(format!("{:?}", cache), "{2: 22, 3: 30, 1: 10}");
        cache.insert(6, 60);
        assert_eq!(format!("{:?}", cache), "{6: 60, 2: 22, 3: 30}");
        cache.get(&3);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60, 2: 22}");
        cache.set_capacity(2);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60}");
    }

    #[test]
    fn test_remove() {
        let mut cache = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        cache.insert(4, 40);
        cache.insert(5, 50);
        cache.remove(&3);
        cache.remove(&4);
        assert!(cache.get(&3).is_none());
        assert!(cache.get(&4).is_none());
        cache.insert(6, 60);
        cache.insert(7, 70);
        cache.insert(8, 80);
        assert!(cache.get(&5).is_none());
        assert_opt_eq(cache.get(&6), 60);
        assert_opt_eq(cache.get(&7), 70);
        assert_opt_eq(cache.get(&8), 80);
    }

    #[test]
    fn test_clear() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.clear();
        assert!(cache.get(&1).is_none());
        assert!(cache.get(&2).is_none());
        assert_eq!(format!("{:?}", cache), "{}");
    }
}
<commit_msg>remove redundant `{Send, Sync}` impls<commit_after>// Copyright 2013 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.

//! A cache that holds a limited number of key-value pairs. When the
//! capacity of the cache is exceeded, the least-recently-used
//! (where "used" means a look-up or putting the pair into the cache)
//! pair is automatically removed.
//!
//! # Examples
//!
//! ```
//! # extern crate "lru-cache" as lru_cache;
//! # fn main() {
//! use lru_cache::LruCache;
//!
//! let mut cache = LruCache::new(2);
//!
//! cache.insert(1, 10);
//! cache.insert(2, 20);
//! cache.insert(3, 30);
//! assert!(cache.get(&1).is_none());
//! assert_eq!(*cache.get(&2).unwrap(), 20);
//! assert_eq!(*cache.get(&3).unwrap(), 30);
//!
//! cache.insert(2, 22);
//! assert_eq!(*cache.get(&2).unwrap(), 22);
//!
//! cache.insert(6, 60);
//! assert!(cache.get(&3).is_none());
//!
//! cache.set_capacity(1);
//! assert!(cache.get(&2).is_none());
//! # }
//! ```

extern crate "linked-hash-map" as linked_hash_map;

use std::fmt;
use std::hash::Hash;
use std::iter::{IntoIterator, Extend};

use linked_hash_map::LinkedHashMap;

// FIXME(conventions): implement iterators?
// FIXME(conventions): implement indexing?

/// An LRU cache.
#[derive(Clone)]
pub struct LruCache<K, V> where K: Eq + Hash {
    map: LinkedHashMap<K, V>,
    max_size: usize,
}

impl<K: Hash + Eq, V> LruCache<K, V> {
    /// Creates an empty cache that can hold at most `capacity` items.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(10);
    /// # }
    /// ```
    pub fn new(capacity: usize) -> LruCache<K, V> {
        LruCache {
            map: LinkedHashMap::new(),
            max_size: capacity,
        }
    }

    /// Inserts a key-value pair into the cache. If the key already existed, the old value is
    /// returned.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// # }
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        let old_val = self.map.insert(k, v);
        if self.len() > self.capacity() {
            self.remove_lru();
        }
        old_val
    }

    /// Returns the value corresponding to the given key in the cache.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(2, "c");
    /// cache.insert(3, "d");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"c"));
    /// # }
    /// ```
    pub fn get(&mut self, k: &K) -> Option<&V> {
        self.map.get_refresh(k)
    }

    /// Removes the given key from the cache and returns its corresponding value.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(2, "a");
    ///
    /// assert_eq!(cache.remove(&1), None);
    /// assert_eq!(cache.remove(&2), Some("a"));
    /// assert_eq!(cache.remove(&2), None);
    /// assert_eq!(cache.len(), 0);
    /// # }
    /// ```
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Returns the maximum number of key-value pairs the cache can hold.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(2);
    /// assert_eq!(cache.capacity(), 2);
    /// # }
    /// ```
    pub fn capacity(&self) -> usize {
        self.max_size
    }

    /// Sets the number of key-value pairs the cache can hold. Removes
    /// least-recently-used key-value pairs if necessary.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    ///
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(3, "c");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(3);
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    ///
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(1);
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), None);
    /// assert_eq!(cache.get(&3), Some(&"c"));
    /// # }
    /// ```
    pub fn set_capacity(&mut self, capacity: usize) {
        for _ in capacity..self.len() {
            self.remove_lru();
        }
        self.max_size = capacity;
    }

    #[inline]
    fn remove_lru(&mut self) {
        self.map.pop_front()
    }

    /// Returns the number of key-value pairs in the cache.
    pub fn len(&self) -> usize { self.map.len() }

    /// Returns `true` if the cache contains no key-value pairs.
    pub fn is_empty(&self) -> bool { self.map.is_empty() }

    /// Removes all key-value pairs from the cache.
    pub fn clear(&mut self) { self.map.clear(); }

}

impl<K: Hash + Eq, V> Extend<(K, V)> for LruCache<K, V> {
    fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl<A: fmt::Debug + Hash + Eq, B: fmt::Debug> fmt::Debug for LruCache<A, B> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{{"));

        for (i, (k, v)) in self.map.iter().rev().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}: {:?}", *k, *v));
        }

        write!(f, "}}")
    }
}

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

    fn assert_opt_eq<V: PartialEq>(opt: Option<&V>, v: V) {
        assert!(opt.is_some());
        assert!(opt.unwrap() == &v);
    }

    #[test]
    fn test_put_and_get() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_opt_eq(cache.get(&1), 10);
        assert_opt_eq(cache.get(&2), 20);
        assert_eq!(cache.len(), 2);
    }

    #[test]
    fn test_put_update() {
        let mut cache: LruCache<String, Vec<u8>> = LruCache::new(1);
        cache.insert("1".to_string(), vec![10, 10]);
        cache.insert("1".to_string(), vec![10, 19]);
        assert_opt_eq(cache.get(&"1".to_string()), vec![10, 19]);
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_expire_lru() {
        let mut cache: LruCache<String, String> = LruCache::new(2);
        cache.insert("foo1".to_string(), "bar1".to_string());
        cache.insert("foo2".to_string(), "bar2".to_string());
        cache.insert("foo3".to_string(), "bar3".to_string());
        assert!(cache.get(&"foo1".to_string()).is_none());
        cache.insert("foo2".to_string(), "bar2update".to_string());
        cache.insert("foo4".to_string(), "bar4".to_string());
        assert!(cache.get(&"foo3".to_string()).is_none());
    }

    #[test]
    fn test_pop() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_eq!(cache.len(), 2);
        let opt1 = cache.remove(&1);
        assert!(opt1.is_some());
        assert_eq!(opt1.unwrap(), 10);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_change_capacity() {
        let mut cache = LruCache::new(2);
        assert_eq!(cache.capacity(), 2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.set_capacity(1);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.capacity(), 1);
    }

    #[test]
    fn test_debug() {
        let mut cache: LruCache<i32, i32> = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        assert_eq!(format!("{:?}", cache), "{3: 30, 2: 20, 1: 10}");
        cache.insert(2, 22);
        assert_eq!(format!("{:?}", cache), "{2: 22, 3: 30, 1: 10}");
        cache.insert(6, 60);
        assert_eq!(format!("{:?}", cache), "{6: 60, 2: 22, 3: 30}");
        cache.get(&3);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60, 2: 22}");
        cache.set_capacity(2);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60}");
    }

    #[test]
    fn test_remove() {
        let mut cache = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        cache.insert(4, 40);
        cache.insert(5, 50);
        cache.remove(&3);
        cache.remove(&4);
        assert!(cache.get(&3).is_none());
        assert!(cache.get(&4).is_none());
        cache.insert(6, 60);
        cache.insert(7, 70);
        cache.insert(8, 80);
        assert!(cache.get(&5).is_none());
        assert_opt_eq(cache.get(&6), 60);
        assert_opt_eq(cache.get(&7), 70);
        assert_opt_eq(cache.get(&8), 80);
    }

    #[test]
    fn test_clear() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.clear();
        assert!(cache.get(&1).is_none());
        assert!(cache.get(&2).is_none());
        assert_eq!(format!("{:?}", cache), "{}");
    }
}
<|endoftext|>


<commit_before>// DOCS

extern crate tempdir;

use std::error::Error as ErrorTrait;
use std::fmt;
use std::io;
use std::fs;
use std::borrow::Borrow;
use std::path;
use std::convert::AsRef;

use tempdir::TempDir;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

#[derive(Clone,Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite
}

/// Represents an error raised by `AtomicFile.write`.
#[derive(Debug)]
pub enum Error<E> {
    /// The error originated in the library itself, while it was either creating a temporary file
    /// or moving the file into place.
    Internal(io::Error),
    /// The error originated in the user-supplied callback.
    User(E)
}

impl Into<io::Error> for Error<io::Error> {
    fn into(self) -> io::Error {
        match self {
            Error::Internal(x) => x,
            Error::User(x) => x
        }
    }
}

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

impl<E: ErrorTrait> ErrorTrait for Error<E> {
    fn description(&self) -> &str {
        match *self {
            Error::Internal(ref e) => e.description(),
            Error::User(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&ErrorTrait> {
        match *self {
            Error::Internal(ref e) => Some(e),
            Error::User(ref e) => Some(e)
        }
    }
}

pub struct AtomicFile {
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    tmpdir: path::PathBuf
}

impl AtomicFile {
    /// Helper for writing to `path` in write-only mode.
    ///
    /// If `DisallowOverwrite` is given, errors will be returned from `self.write(...)` if the file
    /// exists.
    pub fn new<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior) -> Self {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(p, overwrite, p.parent().unwrap_or(p))
    }

    pub fn new_with_tmpdir<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior, tmpdir: P) -> Self {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite: overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf()
        }
    }

    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path())
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path { &self.path.borrow() }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    pub fn write<T, E, F>(&self, f: F) -> Result<T, Error<E>> where
        F: FnOnce(&mut fs::File) -> Result<T, E>
    {
        let tmpdir = try!(TempDir::new_in(
            &self.tmpdir,
            ".atomicwrite"
        ).map_err(Error::Internal));

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = {
            let mut tmpfile = try!(fs::File::create(&tmppath).map_err(Error::Internal));
            try!(f(&mut tmpfile).map_err(Error::User))
        };
        try!(self.commit(&tmppath).map_err(Error::Internal));
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    extern crate nix;

    use std::{io,fs,path};
    use std::os::unix::io::AsRawFd;

    fn fsync_dir(x: &path::Path) -> io::Result<()> {
        let f = try!(fs::File::open(x));
        try!(nix::unistd::fsync(f.as_raw_fd()));
        Ok(())
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::rename(src, dst));

        let dst_directory = dst.parent().unwrap();
        try!(fsync_dir(dst_directory));
        Ok(())
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::hard_link(src, dst));
        try!(fs::remove_file(src));

        let src_directory = src.parent().unwrap();
        let dst_directory = dst.parent().unwrap();
        try!(fsync_dir(dst_directory));
        if src_directory != dst_directory { try!(fsync_dir(src_directory)); }
        Ok(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate kernel32 as win32kernel;

    use std::{io,path};
    use std::ffi::OsStr;
    use std::os::windows::ffi::OsStrExt;

    macro_rules! call {
        ($e: expr) => (
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::last_os_error())
            }
        )
    }

    fn path_to_windows_str<T: AsRef<OsStr>>(x: T) -> Vec<winapi::WCHAR> {
        x.as_ref().encode_wide().chain(Some(0)).collect()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src).as_ptr(), path_to_windows_str(dst).as_ptr(),
            winapi::MOVEFILE_WRITE_THROUGH | winapi::MOVEFILE_REPLACE_EXISTING
        )})
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src).as_ptr(), path_to_windows_str(dst).as_ptr(),
            winapi::MOVEFILE_WRITE_THROUGH
        )})
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<commit_msg>Fixup<commit_after>// DOCS

extern crate tempdir;

use std::error::Error as ErrorTrait;
use std::fmt;
use std::io;
use std::fs;
use std::borrow::Borrow;
use std::path;
use std::convert::AsRef;

use tempdir::TempDir;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

#[derive(Clone,Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite
}

/// Represents an error raised by `AtomicFile.write`.
#[derive(Debug)]
pub enum Error<E> {
    /// The error originated in the library itself, while it was either creating a temporary file
    /// or moving the file into place.
    Internal(io::Error),
    /// The error originated in the user-supplied callback.
    User(E)
}

impl From<Error<io::Error>> for io::Error {
    fn from(e: Error<io::Error>) -> Self {
        match e {
            Error::Internal(x) => x,
            Error::User(x) => x
        }
    }
}

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

impl<E: ErrorTrait> ErrorTrait for Error<E> {
    fn description(&self) -> &str {
        match *self {
            Error::Internal(ref e) => e.description(),
            Error::User(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&ErrorTrait> {
        match *self {
            Error::Internal(ref e) => Some(e),
            Error::User(ref e) => Some(e)
        }
    }
}

pub struct AtomicFile {
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    tmpdir: path::PathBuf
}

impl AtomicFile {
    /// Helper for writing to `path` in write-only mode.
    ///
    /// If `DisallowOverwrite` is given, errors will be returned from `self.write(...)` if the file
    /// exists.
    pub fn new<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior) -> Self {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(p, overwrite, p.parent().unwrap_or(p))
    }

    pub fn new_with_tmpdir<P: AsRef<path::Path>>(path: P, overwrite: OverwriteBehavior, tmpdir: P) -> Self {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite: overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf()
        }
    }

    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path())
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path { &self.path.borrow() }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    pub fn write<T, E, F>(&self, f: F) -> Result<T, Error<E>> where
        F: FnOnce(&mut fs::File) -> Result<T, E>
    {
        let tmpdir = try!(TempDir::new_in(
            &self.tmpdir,
            ".atomicwrite"
        ).map_err(Error::Internal));

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = {
            let mut tmpfile = try!(fs::File::create(&tmppath).map_err(Error::Internal));
            try!(f(&mut tmpfile).map_err(Error::User))
        };
        try!(self.commit(&tmppath).map_err(Error::Internal));
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    extern crate nix;

    use std::{io,fs,path};
    use std::os::unix::io::AsRawFd;

    fn fsync_dir(x: &path::Path) -> io::Result<()> {
        let f = try!(fs::File::open(x));
        try!(nix::unistd::fsync(f.as_raw_fd()));
        Ok(())
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::rename(src, dst));

        let dst_directory = dst.parent().unwrap();
        try!(fsync_dir(dst_directory));
        Ok(())
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        try!(fs::hard_link(src, dst));
        try!(fs::remove_file(src));

        let src_directory = src.parent().unwrap();
        let dst_directory = dst.parent().unwrap();
        try!(fsync_dir(dst_directory));
        if src_directory != dst_directory { try!(fsync_dir(src_directory)); }
        Ok(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate kernel32 as win32kernel;

    use std::{io,path};
    use std::ffi::OsStr;
    use std::os::windows::ffi::OsStrExt;

    macro_rules! call {
        ($e: expr) => (
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::last_os_error())
            }
        )
    }

    fn path_to_windows_str<T: AsRef<OsStr>>(x: T) -> Vec<winapi::WCHAR> {
        x.as_ref().encode_wide().chain(Some(0)).collect()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src).as_ptr(), path_to_windows_str(dst).as_ptr(),
            winapi::MOVEFILE_WRITE_THROUGH | winapi::MOVEFILE_REPLACE_EXISTING
        )})
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {win32kernel::MoveFileExW(
            path_to_windows_str(src).as_ptr(), path_to_windows_str(dst).as_ptr(),
            winapi::MOVEFILE_WRITE_THROUGH
        )})
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<|endoftext|>


<commit_before>extern crate libc;

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! ffi_dispatch(
    ($handle: ident, $func: ident, $($arg: expr),*) => (
        ($handle.$func)($($arg),*)
    )
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! ffi_dispatch(
    ($handle: ident, $func: ident, $($arg: expr),*) => (
        $func($($arg),*)
    )
);

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! ffi_dispatch_static(
    ($handle: ident, $name: ident) => (
        $handle.$name
    )
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! ffi_dispatch_static(
    ($handle: ident, $name: ident) => (
        &$name
    )
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! external_library(
    ($structname: ident, $link: expr,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        #[link(name = $link)]
        extern {
            $($(
                pub static $sname: $stype;
            )+)*
            $($(
                pub fn $fname($(_: $farg),*) -> $fret;
            )+)*
            $($(
                pub fn $vname($(_: $vargs),+ , ...) -> $vret;
            )+)*
        }
    );
);

pub enum DlError {
    NotFound,
    MissingSymbol(&'static str)
}

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! external_library(
    (__struct, $structname: ident,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        pub struct $structname {
            $($(
                pub $sname: &'static $stype,
            )+)*
            $($(
                pub $fname: unsafe extern fn($($farg),*) -> $fret,
            )+)*
            $($(
                pub $vname: unsafe extern "C" fn($($vargs),+ , ...) -> $vret,
            )+)*
        }
    );
    (__impl, $structname: ident,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
    impl $structname {
        pub fn open(name: &str) -> Result<$structname, $crate::DlError> {
            let cname = match ::std::ffi::CString::new(name) {
                Ok(cs) => cs,
                Err(_) => return Err($crate::DlError::NotFound)
            };
            unsafe {
                let dl = $crate::ffi::dlopen(cname.as_bytes_with_nul().as_ptr() as *const _, 1);
                if dl.is_null() {
                    return Err($crate::DlError::NotFound);
                }
                $crate::ffi::dlerror();
                let s = $structname {
                    $($($sname: {
                        let s_name = concat!(stringify!($sname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                    $($($fname: {
                        let s_name = concat!(stringify!($fname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                    $($($vname: {
                        let s_name = concat!(stringify!($vname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                };
                Ok(s)
            }
        }
    }
    );
    ($structname: ident, $link: expr,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        external_library!(__struct,
            $structname, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
           $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
        external_library!(__impl,
            $structname, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
           $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
        unsafe impl Sync for $structname { }
    );
);

pub mod ffi {
    use libc::{c_char, c_int, c_void};
    extern {
        pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
        pub fn dlerror() -> *mut c_char;
        pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
        pub fn dlclose(handle: *mut c_void) -> c_int;
    }
}<commit_msg>Provide macros for fixed dlopen/linked library.<commit_after>extern crate libc;

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! ffi_dispatch(
    ($handle: ident, $func: ident, $($arg: expr),*) => (
        ($handle.$func)($($arg),*)
    )
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! ffi_dispatch(
    ($handle: ident, $func: ident, $($arg: expr),*) => (
        $func($($arg),*)
    )
);

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! ffi_dispatch_static(
    ($handle: ident, $name: ident) => (
        $handle.$name
    )
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! ffi_dispatch_static(
    ($handle: ident, $name: ident) => (
        &$name
    )
);

#[macro_export]
macro_rules! link_external_library(
    ($link: expr,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        #[link(name = $link)]
        extern {
            $($(
                pub static $sname: $stype;
            )+)*
            $($(
                pub fn $fname($(_: $farg),*) -> $fret;
            )+)*
            $($(
                pub fn $vname($(_: $vargs),+ , ...) -> $vret;
            )+)*
        }
    );
);

pub enum DlError {
    NotFound,
    MissingSymbol(&'static str)
}

#[macro_export]
macro_rules! dlopen_external_library(
    (__struct, $structname: ident,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        pub struct $structname {
            $($(
                pub $sname: &'static $stype,
            )+)*
            $($(
                pub $fname: unsafe extern fn($($farg),*) -> $fret,
            )+)*
            $($(
                pub $vname: unsafe extern "C" fn($($vargs),+ , ...) -> $vret,
            )+)*
        }
    );
    (__impl, $structname: ident,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
    impl $structname {
        pub fn open(name: &str) -> Result<$structname, $crate::DlError> {
            let cname = match ::std::ffi::CString::new(name) {
                Ok(cs) => cs,
                Err(_) => return Err($crate::DlError::NotFound)
            };
            unsafe {
                let dl = $crate::ffi::dlopen(cname.as_bytes_with_nul().as_ptr() as *const _, 1);
                if dl.is_null() {
                    return Err($crate::DlError::NotFound);
                }
                $crate::ffi::dlerror();
                let s = $structname {
                    $($($sname: {
                        let s_name = concat!(stringify!($sname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                    $($($fname: {
                        let s_name = concat!(stringify!($fname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                    $($($vname: {
                        let s_name = concat!(stringify!($vname), "\0");
                        let symbol = $crate::ffi::dlsym(dl, s_name.as_ptr() as *const _);
                        if !$crate::ffi::dlerror().is_null() {
                            return Err($crate::DlError::MissingSymbol(s_name))
                        }
                        ::std::mem::transmute(symbol)
                    },
                    )+)*
                };
                Ok(s)
            }
        }
    }
    );
    ($structname: ident,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        dlopen_external_library!(__struct,
            $structname, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
            $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
        dlopen_external_library!(__impl,
            $structname, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
            $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
        unsafe impl Sync for $structname { }
    );
);

#[cfg(not(feature = "dlopen"))]
#[macro_export]
macro_rules! external_library(
    ($structname: ident, $link: expr,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        link_external_library!(
            $link, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
            $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
    );
);

#[cfg(feature = "dlopen")]
#[macro_export]
macro_rules! external_library(
    ($structname: ident, $link: expr,
        $(statics: $($sname: ident: $stype: ty),+)|*
        $(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+)|*
        $(varargs: $(fn $vname: ident($($vargs: ty),+ ...) -> $vret: ty),+)|*
    ) => (
        dlopen_external_library!(
            $structname, $(statics: $($sname: $stype),+)|*
            $(functions: $(fn $fname($($farg),*) -> $fret),+)|*
            $(varargs: $(fn $vname($($vargs),+ ...) -> $vret),+)|*
        );
    );
);

pub mod ffi {
    use libc::{c_char, c_int, c_void};
    extern {
        pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
        pub fn dlerror() -> *mut c_char;
        pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
        pub fn dlclose(handle: *mut c_void) -> c_int;
    }
}<|endoftext|>


<commit_before>extern crate redis;

use std::time::Duration;

use redis::{Connection, RedisError, cmd};

fn duration_to_millis(d: &Duration) -> u64 {
    (d.subsec_nanos() / 1_000_000) as u64 + d.as_secs()
}

macro_rules! option_arg {
    ($disque: expr, $name: expr, $param: expr) => (
        match $param {
            Some(u) => $disque.arg($name).arg(u),
            None => &mut $disque,
        };
    )
}
pub struct Disque {
    connection: Connection,
}

impl Disque {
    pub fn open(url: &str) -> Result<Disque, RedisError> {
        let client = try!(redis::Client::open(url));
        let connection = try!(client.get_connection());
        Ok(Disque { connection: connection })
    }

    pub fn hello(&self) -> Result<Vec<Vec<u8>>, RedisError> {
        cmd("HELLO").query(&self.connection)
    }

    pub fn addjob(&self, queue_name: &[u8], job: &[u8], timeout: Duration,
            replicate: Option<usize>, delay: Option<Duration>,
            retry: Option<Duration>, ttl: Option<Duration>,
            maxlen: Option<usize>, async: bool,
            ) -> Result<String, RedisError> {
        let mut c = cmd("ADDJOB");
        c
            .arg(queue_name)
            .arg(job)
            .arg(duration_to_millis(&timeout));
        option_arg!(c, "REPLICATE", replicate);
        option_arg!(c, "DELAY", delay.map(|x| x.as_secs()));
        option_arg!(c, "RETRY", retry.map(|x| x.as_secs()));
        option_arg!(c, "TTL", ttl.map(|x| x.as_secs()));
        option_arg!(c, "MAXLEN", maxlen);
        if async { c.arg("ASYNC"); }
        c.query(&self.connection)
    }

    pub fn getjob_count(&self, nohang: bool, timeout: Option<Duration>,
            count: usize, withcounters: bool, queues: &[&[u8]]
            ) -> Result<Vec<Vec<Vec<u8>>>, RedisError> {
        let mut c = cmd("GETJOB");
        if nohang { c.arg("NOHANG"); }
        option_arg!(c, "TIMEOUT", timeout.map(|t| duration_to_millis(&t)));
        c.arg("COUNT").arg(count);
        if withcounters { c.arg("WITHCOUNTERS"); }
        c.arg("FROM");
        for queue in queues { c.arg(*queue); }
        c.query(&self.connection)
    }
}

#[cfg(test)]
fn conn() -> Disque {
    Disque::open("redis://127.0.0.1:7711/").unwrap()
}

#[test]
fn can_connect() {
    conn();
}

#[test]
fn hello() {
    let disque = conn();
    disque.hello().unwrap();
}

#[test]
fn addjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue", b"job", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert_eq!(jobid.len(), 48);
    assert_eq!(&jobid[..2], "DI");
    assert_eq!(&jobid[46..], "SQ");
}

#[test]
fn getjob_count() {
    let disque = conn();
    let j1 = disque.addjob(b"queue1", b"job1", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let j2 = disque.addjob(b"queue2", b"job2", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    disque.addjob(b"queue3", b"job3", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let jobs = disque.getjob_count(false, None, 3, true, &[b"queue1", b"queue2"]).unwrap();
    assert_eq!(jobs.len(), 2);
    assert_eq!(jobs[0][0], b"queue1");
    assert_eq!(jobs[0][1], j1.into_bytes());
    assert_eq!(jobs[0][2], b"job1");
    assert_eq!(jobs[1][0], b"queue2");
    assert_eq!(jobs[1][1], j2.into_bytes());
    assert_eq!(jobs[1][2], b"job2");
}
<commit_msg>Add getjob<commit_after>extern crate redis;

use std::time::Duration;

use redis::{Connection, RedisError, cmd};

fn duration_to_millis(d: &Duration) -> u64 {
    (d.subsec_nanos() / 1_000_000) as u64 + d.as_secs()
}

macro_rules! option_arg {
    ($disque: expr, $name: expr, $param: expr) => (
        match $param {
            Some(u) => $disque.arg($name).arg(u),
            None => &mut $disque,
        };
    )
}
pub struct Disque {
    connection: Connection,
}

impl Disque {
    pub fn open(url: &str) -> Result<Disque, RedisError> {
        let client = try!(redis::Client::open(url));
        let connection = try!(client.get_connection());
        Ok(Disque { connection: connection })
    }

    pub fn hello(&self) -> Result<Vec<Vec<u8>>, RedisError> {
        cmd("HELLO").query(&self.connection)
    }

    pub fn addjob(&self, queue_name: &[u8], job: &[u8], timeout: Duration,
            replicate: Option<usize>, delay: Option<Duration>,
            retry: Option<Duration>, ttl: Option<Duration>,
            maxlen: Option<usize>, async: bool,
            ) -> Result<String, RedisError> {
        let mut c = cmd("ADDJOB");
        c
            .arg(queue_name)
            .arg(job)
            .arg(duration_to_millis(&timeout));
        option_arg!(c, "REPLICATE", replicate);
        option_arg!(c, "DELAY", delay.map(|x| x.as_secs()));
        option_arg!(c, "RETRY", retry.map(|x| x.as_secs()));
        option_arg!(c, "TTL", ttl.map(|x| x.as_secs()));
        option_arg!(c, "MAXLEN", maxlen);
        if async { c.arg("ASYNC"); }
        c.query(&self.connection)
    }

    pub fn getjob_count(&self, nohang: bool, timeout: Option<Duration>,
            count: usize, withcounters: bool, queues: &[&[u8]]
            ) -> Result<Vec<Vec<Vec<u8>>>, RedisError> {
        let mut c = cmd("GETJOB");
        if nohang { c.arg("NOHANG"); }
        option_arg!(c, "TIMEOUT", timeout.map(|t| duration_to_millis(&t)));
        c.arg("COUNT").arg(count);
        if withcounters { c.arg("WITHCOUNTERS"); }
        c.arg("FROM");
        for queue in queues { c.arg(*queue); }
        c.query(&self.connection)
    }

    pub fn getjob(&self, nohang: bool, timeout: Option<Duration>,
            withcounters: bool, queues: &[&[u8]]
            ) -> Result<Option<Vec<Vec<u8>>>, RedisError> {
        let mut jobs = try!(self.getjob_count(nohang, timeout, 1, withcounters,
                    queues));
        Ok(jobs.pop())
    }
}

#[cfg(test)]
fn conn() -> Disque {
    Disque::open("redis://127.0.0.1:7711/").unwrap()
}

#[test]
fn can_connect() {
    conn();
}

#[test]
fn hello() {
    let disque = conn();
    disque.hello().unwrap();
}

#[test]
fn addjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue", b"job", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert_eq!(jobid.len(), 48);
    assert_eq!(&jobid[..2], "DI");
    assert_eq!(&jobid[46..], "SQ");
}

#[test]
fn getjob_count() {
    let disque = conn();
    let j1 = disque.addjob(b"queue1", b"job1", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let j2 = disque.addjob(b"queue2", b"job2", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    disque.addjob(b"queue3", b"job3", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let jobs = disque.getjob_count(false, None, 3, true, &[b"queue1", b"queue2"]).unwrap();
    assert_eq!(jobs.len(), 2);
    assert_eq!(jobs[0][0], b"queue1");
    assert_eq!(jobs[0][1], j1.into_bytes());
    assert_eq!(jobs[0][2], b"job1");
    assert_eq!(jobs[1][0], b"queue2");
    assert_eq!(jobs[1][1], j2.into_bytes());
    assert_eq!(jobs[1][2], b"job2");
}

#[test]
fn getjob() {
    let disque = conn();
    let j1 = disque.addjob(b"queue4", b"job4", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let job = disque.getjob(false, None, true, &[b"queue4", b"queue5"]).unwrap().unwrap();
    assert_eq!(job[0], b"queue4");
    assert_eq!(job[1], j1.into_bytes());
    assert_eq!(job[2], b"job4");
}
<|endoftext|>


<commit_before>#![feature(core)]

//! A TCOD back-end for the Piston game engine.

extern crate input;
#[macro_use]
extern crate quack;
extern crate tcod;
extern crate window;

use input::{ keyboard, Button, MouseButton, Input, Motion };
use tcod::Console;
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};

pub struct TcodWindow {
    pub window: tcod::Console,
    title: String,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    mouse_state_prev: tcod::MouseState,
    exit_on_esc: bool,
}

impl TcodWindow {
    pub fn new(settings: WindowSettings) -> TcodWindow {
        let window = Console::init_root(
            settings.size[0] as i32,
            settings.size[1] as i32,
            &*settings.title,
            false
        );

        TcodWindow {
            window: window,
            title: settings.title,
            should_close: false,
            mouse_relative: None,
            // TODO: determine if there's a better way to initialize the
            // MouseState.
            mouse_state_prev: tcod::MouseState {
                x: 0isize,
                y: 0isize,
                dx: 0isize,
                dy: 0isize,
                cx: 0isize,
                cy: 0isize,
                dcx: 0isize,
                dcy: 0isize,
                lbutton: false,
                rbutton: false,
                mbutton: false,
                lbutton_pressed: false,
                rbutton_pressed: false,
                mbutton_pressed: false,
                wheel_up: false,
                wheel_down: false,
            },
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use tcod::KeyCode;
        use tcod::Key::Special;
        use tcod::system::Event;

        match self.mouse_relative {
            Some((x, y)) => {
                self.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        let (flags, event) = tcod::system::check_for_event(tcod::ANY);
        match (flags, event) {
            (tcod::KEY_PRESS, Event::Key(ref key_state)) => {
                if self.exit_on_esc
                && key_state.key == Special(KeyCode::Escape) {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(tcod_map_key(key_state.key))));
                }
            },
            (tcod::KEY_RELEASE, Event::Key(ref key_state)) => {
                return Some(Input::Release(Button::Keyboard(tcod_map_key(key_state.key))));
            },
            (tcod::MOUSE_PRESS, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Press(Button::Mouse(button)));
            },
            (tcod::MOUSE_RELEASE, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Release(Button::Mouse(button)));
            },
            (tcod::MOUSE_MOVE, Event::Mouse(ref mouse_state)) => {
                // TODO: figure out why mouse_state.dx and mouse_state.dy
                // don't work.
                self.mouse_relative = Some((
                    (mouse_state.x - self.mouse_state_prev.x) as f64,
                    (mouse_state.y - self.mouse_state_prev.y) as f64
                ));
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Move(Motion::MouseCursor(mouse_state.x as f64, mouse_state.y as f64)));
            },
            (_, _) => {}
        }
        None
    }
}

quack! {
    _obj: TcodWindow[]
    get:
        fn () -> ShouldClose [] { ShouldClose(_obj.should_close) }
        fn () -> Size [] {
            let (w, h) = (_obj.window.width(), _obj.window.height());
            Size([w as u32, h as u32])
        }
        fn () -> DrawSize [] {
            //let (w, h) = _obj.window.get_drawable_size();
            let (w, h) = (_obj.window.width(), _obj.window.height());
            DrawSize([w as u32, h as u32])
        }
        // TODO: Remove the .clone()
        fn () -> Title [] { Title(_obj.title.clone()) }
        fn () -> ExitOnEsc [] { ExitOnEsc(_obj.exit_on_esc) }
    set:
        fn (val: CaptureCursor) [] {
            //sdl2::mouse::set_relative_mouse_mode(val.0)
        }
        fn (val: ShouldClose) [] { _obj.should_close = val.0 }
        fn (val: Title) [] {
            Console::set_window_title(&*val.0);
            _obj.title = val.0
        }
        fn (val: ExitOnEsc) [] { _obj.exit_on_esc = val.0 }
    action:
        fn (__: SwapBuffers) -> () [] {
            //_obj.window.gl_swap_window()
            Console::flush()
        }
        fn (__: PollEvent) -> Option<Input> [] { _obj.poll_event() }
}

pub fn tcod_map_key(key: tcod::Key) -> keyboard::Key {
    use input::keyboard::Key;
    use std::num::FromPrimitive;
    match key {
        tcod::Key::Printable(keycode) => FromPrimitive::from_u64(keycode as u64).unwrap(),
        tcod::Key::Special(keycode) => {
            match keycode {
                tcod::KeyCode::NoKey => Key::Unknown,
                tcod::KeyCode::Escape => Key::Escape,
                tcod::KeyCode::Backspace => Key::Backspace,
                tcod::KeyCode::Tab => Key::Tab,
                tcod::KeyCode::Enter => Key::Return,
                tcod::KeyCode::Shift => Key::LShift, // TODO: find RShift
                tcod::KeyCode::Control => Key::LCtrl,
                tcod::KeyCode::Alt => Key::LAlt,
                tcod::KeyCode::Pause => Key::Pause,
                tcod::KeyCode::Capslock => Key::CapsLock,
                tcod::KeyCode::Pageup => Key::PageUp,
                tcod::KeyCode::Pagedown => Key::PageDown,
                tcod::KeyCode::End => Key::End,
                tcod::KeyCode::Home => Key::Home,
                tcod::KeyCode::Up => Key::Up,
                tcod::KeyCode::Left => Key::Left,
                tcod::KeyCode::Right => Key::Right,
                tcod::KeyCode::Down => Key::Down,
                tcod::KeyCode::PrintScreen => Key::PrintScreen,
                tcod::KeyCode::Insert => Key::Insert,
                tcod::KeyCode::Delete => Key::Delete,
                tcod::KeyCode::LeftWin => Key::LGui,
                tcod::KeyCode::RightWin => Key::RGui,
                tcod::KeyCode::Apps => Key::Application,
                // The numbers on the alphanum section of the keyboard
                tcod::KeyCode::Number0 => Key::D0,
                tcod::KeyCode::Number1 => Key::D1,
                tcod::KeyCode::Number2 => Key::D2,
                tcod::KeyCode::Number3 => Key::D3,
                tcod::KeyCode::Number4 => Key::D4,
                tcod::KeyCode::Number5 => Key::D5,
                tcod::KeyCode::Number6 => Key::D6,
                tcod::KeyCode::Number7 => Key::D7,
                tcod::KeyCode::Number8 => Key::D8,
                tcod::KeyCode::Number9 => Key::D9,
                // The numbers on the numeric keypad
                tcod::KeyCode::NumPad0 => Key::NumPad0,
                tcod::KeyCode::NumPad1 => Key::NumPad1,
                tcod::KeyCode::NumPad2 => Key::NumPad2,
                tcod::KeyCode::NumPad3 => Key::NumPad3,
                tcod::KeyCode::NumPad4 => Key::NumPad4,
                tcod::KeyCode::NumPad5 => Key::NumPad5,
                tcod::KeyCode::NumPad6 => Key::NumPad6,
                tcod::KeyCode::NumPad7 => Key::NumPad7,
                tcod::KeyCode::NumPad8 => Key::NumPad8,
                tcod::KeyCode::NumPad9 => Key::NumPad9,
                tcod::KeyCode::NumPadAdd => Key::NumPadPlus,
                tcod::KeyCode::NumPadSubtract => Key::NumPadMinus,
                tcod::KeyCode::NumPadDivide => Key::NumPadDivide,
                tcod::KeyCode::NumPadMultiply => Key::NumPadMultiply,
                tcod::KeyCode::NumPadDecimal => Key::NumPadDecimal,
                tcod::KeyCode::NumPadEnter => Key::NumPadEnter,
                tcod::KeyCode::F1 => Key::F1,
                tcod::KeyCode::F2 => Key::F2,
                tcod::KeyCode::F3 => Key::F3,
                tcod::KeyCode::F4 => Key::F4,
                tcod::KeyCode::F5 => Key::F5,
                tcod::KeyCode::F6 => Key::F6,
                tcod::KeyCode::F7 => Key::F7,
                tcod::KeyCode::F8 => Key::F8,
                tcod::KeyCode::F9 => Key::F9,
                tcod::KeyCode::F10 => Key::F10,
                tcod::KeyCode::F11 => Key::F11,
                tcod::KeyCode::F12 => Key::F12,
                tcod::KeyCode::NUMLOCK => Key::NumLockClear,
                tcod::KeyCode::SCROLLLOCK => Key::ScrollLock,
                tcod::KeyCode::Spacebar => Key::Space,
                // TODO: check if this is correct.
                tcod::KeyCode::Char => Key::Unknown,
            }
        }
    }
}

pub fn tcod_map_mouse(prev_state: tcod::MouseState, state: &tcod::MouseState) -> MouseButton {
    if prev_state.lbutton != state.lbutton { return MouseButton::Left }
    else if prev_state.rbutton != state.rbutton { return MouseButton::Right }
    else if prev_state.mbutton != state.mbutton { return MouseButton::Middle }
    else { return MouseButton::Unknown }
}
<commit_msg>Prepare for redesign in piston-event_loop. Closes #2.<commit_after>#![feature(core)]

//! A TCOD back-end for the Piston game engine.

extern crate input;
#[macro_use]
extern crate quack;
extern crate tcod;
extern crate window;

use input::{ keyboard, Button, MouseButton, Input, Motion };
use quack::Associative;
use tcod::Console;
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};

pub struct TcodWindow {
    pub window: tcod::Console,
    title: String,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    mouse_state_prev: tcod::MouseState,
    exit_on_esc: bool,
}

impl TcodWindow {
    pub fn new(settings: WindowSettings) -> TcodWindow {
        let window = Console::init_root(
            settings.size[0] as i32,
            settings.size[1] as i32,
            &*settings.title,
            false
        );

        TcodWindow {
            window: window,
            title: settings.title,
            should_close: false,
            mouse_relative: None,
            // TODO: determine if there's a better way to initialize the
            // MouseState.
            mouse_state_prev: tcod::MouseState {
                x: 0isize,
                y: 0isize,
                dx: 0isize,
                dy: 0isize,
                cx: 0isize,
                cy: 0isize,
                dcx: 0isize,
                dcy: 0isize,
                lbutton: false,
                rbutton: false,
                mbutton: false,
                lbutton_pressed: false,
                rbutton_pressed: false,
                mbutton_pressed: false,
                wheel_up: false,
                wheel_down: false,
            },
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use tcod::KeyCode;
        use tcod::Key::Special;
        use tcod::system::Event;

        match self.mouse_relative {
            Some((x, y)) => {
                self.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        let (flags, event) = tcod::system::check_for_event(tcod::ANY);
        match (flags, event) {
            (tcod::KEY_PRESS, Event::Key(ref key_state)) => {
                if self.exit_on_esc
                && key_state.key == Special(KeyCode::Escape) {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(tcod_map_key(key_state.key))));
                }
            },
            (tcod::KEY_RELEASE, Event::Key(ref key_state)) => {
                return Some(Input::Release(Button::Keyboard(tcod_map_key(key_state.key))));
            },
            (tcod::MOUSE_PRESS, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Press(Button::Mouse(button)));
            },
            (tcod::MOUSE_RELEASE, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Release(Button::Mouse(button)));
            },
            (tcod::MOUSE_MOVE, Event::Mouse(ref mouse_state)) => {
                // TODO: figure out why mouse_state.dx and mouse_state.dy
                // don't work.
                self.mouse_relative = Some((
                    (mouse_state.x - self.mouse_state_prev.x) as f64,
                    (mouse_state.y - self.mouse_state_prev.y) as f64
                ));
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Move(Motion::MouseCursor(mouse_state.x as f64, mouse_state.y as f64)));
            },
            (_, _) => {}
        }
        None
    }
}

quack! {
    _obj: TcodWindow[]
    get:
        fn () -> ShouldClose [] { ShouldClose(_obj.should_close) }
        fn () -> Size [] {
            let (w, h) = (_obj.window.width(), _obj.window.height());
            Size([w as u32, h as u32])
        }
        fn () -> DrawSize [] {
            //let (w, h) = _obj.window.get_drawable_size();
            let (w, h) = (_obj.window.width(), _obj.window.height());
            DrawSize([w as u32, h as u32])
        }
        // TODO: Remove the .clone()
        fn () -> Title [] { Title(_obj.title.clone()) }
        fn () -> ExitOnEsc [] { ExitOnEsc(_obj.exit_on_esc) }
    set:
        fn (val: CaptureCursor) [] {
            //sdl2::mouse::set_relative_mouse_mode(val.0)
        }
        fn (val: ShouldClose) [] { _obj.should_close = val.0 }
        fn (val: Title) [] {
            Console::set_window_title(&*val.0);
            _obj.title = val.0
        }
        fn (val: ExitOnEsc) [] { _obj.exit_on_esc = val.0 }
    action:
        fn (__: SwapBuffers) -> () [] {
            //_obj.window.gl_swap_window()
            Console::flush()
        }
        fn (__: PollEvent) -> Option<Input> [] { _obj.poll_event() }
}

impl Associative for (PollEvent, TcodWindow) {
    type Type = Input;
}

pub fn tcod_map_key(key: tcod::Key) -> keyboard::Key {
    use input::keyboard::Key;
    use std::num::FromPrimitive;
    match key {
        tcod::Key::Printable(keycode) => FromPrimitive::from_u64(keycode as u64).unwrap(),
        tcod::Key::Special(keycode) => {
            match keycode {
                tcod::KeyCode::NoKey => Key::Unknown,
                tcod::KeyCode::Escape => Key::Escape,
                tcod::KeyCode::Backspace => Key::Backspace,
                tcod::KeyCode::Tab => Key::Tab,
                tcod::KeyCode::Enter => Key::Return,
                tcod::KeyCode::Shift => Key::LShift, // TODO: find RShift
                tcod::KeyCode::Control => Key::LCtrl,
                tcod::KeyCode::Alt => Key::LAlt,
                tcod::KeyCode::Pause => Key::Pause,
                tcod::KeyCode::Capslock => Key::CapsLock,
                tcod::KeyCode::Pageup => Key::PageUp,
                tcod::KeyCode::Pagedown => Key::PageDown,
                tcod::KeyCode::End => Key::End,
                tcod::KeyCode::Home => Key::Home,
                tcod::KeyCode::Up => Key::Up,
                tcod::KeyCode::Left => Key::Left,
                tcod::KeyCode::Right => Key::Right,
                tcod::KeyCode::Down => Key::Down,
                tcod::KeyCode::PrintScreen => Key::PrintScreen,
                tcod::KeyCode::Insert => Key::Insert,
                tcod::KeyCode::Delete => Key::Delete,
                tcod::KeyCode::LeftWin => Key::LGui,
                tcod::KeyCode::RightWin => Key::RGui,
                tcod::KeyCode::Apps => Key::Application,
                // The numbers on the alphanum section of the keyboard
                tcod::KeyCode::Number0 => Key::D0,
                tcod::KeyCode::Number1 => Key::D1,
                tcod::KeyCode::Number2 => Key::D2,
                tcod::KeyCode::Number3 => Key::D3,
                tcod::KeyCode::Number4 => Key::D4,
                tcod::KeyCode::Number5 => Key::D5,
                tcod::KeyCode::Number6 => Key::D6,
                tcod::KeyCode::Number7 => Key::D7,
                tcod::KeyCode::Number8 => Key::D8,
                tcod::KeyCode::Number9 => Key::D9,
                // The numbers on the numeric keypad
                tcod::KeyCode::NumPad0 => Key::NumPad0,
                tcod::KeyCode::NumPad1 => Key::NumPad1,
                tcod::KeyCode::NumPad2 => Key::NumPad2,
                tcod::KeyCode::NumPad3 => Key::NumPad3,
                tcod::KeyCode::NumPad4 => Key::NumPad4,
                tcod::KeyCode::NumPad5 => Key::NumPad5,
                tcod::KeyCode::NumPad6 => Key::NumPad6,
                tcod::KeyCode::NumPad7 => Key::NumPad7,
                tcod::KeyCode::NumPad8 => Key::NumPad8,
                tcod::KeyCode::NumPad9 => Key::NumPad9,
                tcod::KeyCode::NumPadAdd => Key::NumPadPlus,
                tcod::KeyCode::NumPadSubtract => Key::NumPadMinus,
                tcod::KeyCode::NumPadDivide => Key::NumPadDivide,
                tcod::KeyCode::NumPadMultiply => Key::NumPadMultiply,
                tcod::KeyCode::NumPadDecimal => Key::NumPadDecimal,
                tcod::KeyCode::NumPadEnter => Key::NumPadEnter,
                tcod::KeyCode::F1 => Key::F1,
                tcod::KeyCode::F2 => Key::F2,
                tcod::KeyCode::F3 => Key::F3,
                tcod::KeyCode::F4 => Key::F4,
                tcod::KeyCode::F5 => Key::F5,
                tcod::KeyCode::F6 => Key::F6,
                tcod::KeyCode::F7 => Key::F7,
                tcod::KeyCode::F8 => Key::F8,
                tcod::KeyCode::F9 => Key::F9,
                tcod::KeyCode::F10 => Key::F10,
                tcod::KeyCode::F11 => Key::F11,
                tcod::KeyCode::F12 => Key::F12,
                tcod::KeyCode::NUMLOCK => Key::NumLockClear,
                tcod::KeyCode::SCROLLLOCK => Key::ScrollLock,
                tcod::KeyCode::Spacebar => Key::Space,
                // TODO: check if this is correct.
                tcod::KeyCode::Char => Key::Unknown,
            }
        }
    }
}

pub fn tcod_map_mouse(prev_state: tcod::MouseState, state: &tcod::MouseState) -> MouseButton {
    if prev_state.lbutton != state.lbutton { return MouseButton::Left }
    else if prev_state.rbutton != state.rbutton { return MouseButton::Right }
    else if prev_state.mbutton != state.mbutton { return MouseButton::Middle }
    else { return MouseButton::Unknown }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="nightly", feature(plugin))]
#![cfg_attr(feature="nightly", plugin(clippy))]
#![cfg_attr(feature="nightly", deny(warnings))]

#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
extern crate num;

#[macro_use]
mod macros;

pub use correlator::Correlator;
pub use correlator::CorrelatorFactory;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::{Message, MessageBuilder};
pub use context::ContextMap;
pub use reactor::{EventHandler, SharedData};

pub mod conditions;
pub mod config;
pub mod correlator;
pub mod test_utils;
mod action;
mod message;
mod context;
mod dispatcher;
mod reactor;
mod state;
mod timer;
mod duration;
<commit_msg>lib: make conditions private and reexport Conditions and ConditionsBuilder<commit_after>#![cfg_attr(feature="nightly", feature(plugin))]
#![cfg_attr(feature="nightly", plugin(clippy))]
#![cfg_attr(feature="nightly", deny(warnings))]

#[macro_use]
extern crate maplit;
extern crate env_logger;
extern crate uuid;
extern crate serde;
extern crate serde_json;
extern crate rustc_serialize;
extern crate handlebars;
#[macro_use]
extern crate log;
extern crate num;

#[macro_use]
mod macros;

pub use conditions::{Conditions, ConditionsBuilder};
pub use correlator::Correlator;
pub use correlator::CorrelatorFactory;
pub use config::action::ActionType;
pub use dispatcher::Response;
pub use message::{Message, MessageBuilder};
pub use context::ContextMap;
pub use reactor::{EventHandler, SharedData};

pub mod config;
pub mod correlator;
pub mod test_utils;
mod conditions;
mod action;
mod message;
mod context;
mod dispatcher;
mod reactor;
mod state;
mod timer;
mod duration;
<|endoftext|>


<commit_before>//! A crate that provides the `IpAddr` type, which can represent either an IPv4
//! or an IPv6 address.

use std::fmt;
use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;

/// An IP address, either an IPv4 or IPv6 address.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
pub enum IpAddr {
    /// Representation of an IPv4 address.
    V4(Ipv4Addr),
    /// Representation of an IPv6 address.
    V6(Ipv6Addr),
}

impl fmt::Display for IpAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpAddr::V4(ref a) => a.fmt(fmt),
            IpAddr::V6(ref a) => a.fmt(fmt),
        }
    }
}

impl FromStr for IpAddr {
    type Err = AddrParseError;

    fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
        Ipv4Addr::from_str(s).map(|v4| IpAddr::V4(v4))
            .or_else(|_| {
                Ipv6Addr::from_str(s).map(|v6| IpAddr::V6(v6))
            })
    }
}

#[test]
fn parse_ipv4() {
    let parsed = IpAddr::from_str("192.168.0.1").unwrap();
    let ipv4 = Ipv4Addr::from_str("192.168.0.1").unwrap();
    assert_eq!(IpAddr::V4(ipv4), parsed);
}

#[test]
fn parse_ipv6() {
    let parsed = IpAddr::from_str("2001:0db8::0001").unwrap();
    let ipv6 = Ipv6Addr::from_str("2001:0db8::0001").unwrap();
    assert_eq!(IpAddr::V6(ipv6), parsed);
}

#[test]
fn parse_fails() {
    let parsed = IpAddr::from_str("nonsense");
    assert!(parsed.is_err());
}
<commit_msg>Add SocketAddrExt trait<commit_after>//! A crate that provides the `IpAddr` type, which can represent either an IPv4
//! or an IPv6 address.

use std::fmt;
use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::str::FromStr;

/// An IP address, either an IPv4 or IPv6 address.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
pub enum IpAddr {
    /// Representation of an IPv4 address.
    V4(Ipv4Addr),
    /// Representation of an IPv6 address.
    V6(Ipv6Addr),
}

impl fmt::Display for IpAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpAddr::V4(ref a) => a.fmt(fmt),
            IpAddr::V6(ref a) => a.fmt(fmt),
        }
    }
}

impl FromStr for IpAddr {
    type Err = AddrParseError;

    fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
        Ipv4Addr::from_str(s).map(|v4| IpAddr::V4(v4))
            .or_else(|_| {
                Ipv6Addr::from_str(s).map(|v6| IpAddr::V6(v6))
            })
    }
}

/// Methods to convert between `IpAddr` and `std::net::SocketAddr`
pub trait SocketAddrExt {
    /// Creates a new socket address from the (ip, port) pair.
    fn new(ip: IpAddr, port: u16) -> SocketAddr;
    /// Returns the IP address associated with this socket address.
    fn ip(&self) -> IpAddr;
}

impl SocketAddrExt for SocketAddr {
    fn new(ip: IpAddr, port: u16) -> SocketAddr {
        match ip {
            IpAddr::V4(ipv4_addr) => SocketAddr::V4(SocketAddrV4::new(ipv4_addr, port)),
            IpAddr::V6(ipv6_addr) => SocketAddr::V6(SocketAddrV6::new(ipv6_addr, port, 0, 0)),
        }
    }

    fn ip(&self) -> IpAddr {
        match *self {
            SocketAddr::V4(socket_addr_v4) => IpAddr::V4(*socket_addr_v4.ip()),
            SocketAddr::V6(socket_addr_v6) => IpAddr::V6(*socket_addr_v6.ip()),
        }
    }
}

#[test]
fn parse_ipv4() {
    let parsed = IpAddr::from_str("192.168.0.1").unwrap();
    let ipv4 = Ipv4Addr::from_str("192.168.0.1").unwrap();
    assert_eq!(IpAddr::V4(ipv4), parsed);
}

#[test]
fn parse_ipv6() {
    let parsed = IpAddr::from_str("2001:0db8::0001").unwrap();
    let ipv6 = Ipv6Addr::from_str("2001:0db8::0001").unwrap();
    assert_eq!(IpAddr::V6(ipv6), parsed);
}

#[test]
fn parse_fails() {
    let parsed = IpAddr::from_str("nonsense");
    assert!(parsed.is_err());
}
<|endoftext|>


<commit_before>//! Crate ruma_client_api contains serializable types for the requests and responses for each
//! endpoint in the [Matrix](https://matrix.org/) client API specification. These types can be
//! shared by client and server code.

#![deny(missing_debug_implementations, missing_docs)]
#![feature(associated_consts, proc_macro, try_from)]

extern crate futures;
extern crate hyper;
extern crate ruma_api;
extern crate ruma_api_macros;
extern crate ruma_events;
extern crate ruma_identifiers;
extern crate ruma_signatures;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
extern crate serde_urlencoded;
extern crate url;

/// Endpoints for the r0.x.x versions of the client API specification.
pub mod r0 {
    pub mod account;
    pub mod alias;
    pub mod config;
    pub mod contact;
    pub mod context;
    pub mod directory;
    pub mod filter;
    pub mod media;
    pub mod membership;
    pub mod presence;
    pub mod profile;
    pub mod push;
    pub mod receipt;
    pub mod redact;
    pub mod room;
    pub mod search;
    pub mod send;
    pub mod server;
    pub mod session;
    pub mod sync;
    pub mod tag;
    pub mod typing;
    pub mod voip;
}

pub mod unversioned;
<commit_msg>associated_consts stabilized<commit_after>//! Crate ruma_client_api contains serializable types for the requests and responses for each
//! endpoint in the [Matrix](https://matrix.org/) client API specification. These types can be
//! shared by client and server code.

#![deny(missing_debug_implementations, missing_docs)]
#![feature(proc_macro, try_from)]

extern crate futures;
extern crate hyper;
extern crate ruma_api;
extern crate ruma_api_macros;
extern crate ruma_events;
extern crate ruma_identifiers;
extern crate ruma_signatures;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
extern crate serde_urlencoded;
extern crate url;

/// Endpoints for the r0.x.x versions of the client API specification.
pub mod r0 {
    pub mod account;
    pub mod alias;
    pub mod config;
    pub mod contact;
    pub mod context;
    pub mod directory;
    pub mod filter;
    pub mod media;
    pub mod membership;
    pub mod presence;
    pub mod profile;
    pub mod push;
    pub mod receipt;
    pub mod redact;
    pub mod room;
    pub mod search;
    pub mod send;
    pub mod server;
    pub mod session;
    pub mod sync;
    pub mod tag;
    pub mod typing;
    pub mod voip;
}

pub mod unversioned;
<|endoftext|>


<commit_before>//! Actix web is a small, pragmatic, extremely fast, web framework for Rust.
//!
//! ```rust
//! use actix_web::*;
//! # use std::thread;
//!
//! fn index(req: HttpRequest) -> String {
//!     format!("Hello {}!", &req.match_info()["name"])
//! }
//!
//! fn main() {
//! # thread::spawn(|| {
//!     HttpServer::new(
//!         || Application::new()
//!             .resource("/{name}", |r| r.f(index)))
//!         .bind("127.0.0.1:8080").unwrap()
//!         .run();
//! # });
//! }
//! ```
//!
//! ## Documentation
//!
//! * [User Guide](http://actix.github.io/actix-web/guide/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//! * Supported Rust version: 1.21 or later
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* and *HTTP/2.0* protocols
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Transparent content compression/decompression (br, gzip, deflate)
//! * Configurable request routing
//! * Graceful server shutdown
//! * Multipart streams
//! * SSL support with openssl or native-tls
//! * Middlewares (`Logger`, `Session`, `CORS`, `CSRF`, `DefaultHeaders`)
//! * Built on top of [Actix actor framework](https://github.com/actix/actix).

#![cfg_attr(actix_nightly, feature(
    specialization, // for impl ErrorResponse for std::error::Error
))]
#![cfg_attr(feature = "cargo-clippy", allow(
    decimal_literal_representation,suspicious_arithmetic_impl,))]

#[macro_use]
extern crate log;
extern crate time;
extern crate base64;
extern crate bytes;
extern crate byteorder;
extern crate sha1;
extern crate regex;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_io;
extern crate tokio_core;
extern crate mio;
extern crate net2;
extern crate cookie;
extern crate http;
extern crate httparse;
extern crate http_range;
extern crate mime;
extern crate mime_guess;
extern crate language_tags;
extern crate rand;
extern crate url;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate flate2;
#[cfg(feature="brotli")]
extern crate brotli2;
extern crate encoding;
extern crate percent_encoding;
extern crate smallvec;
extern crate num_cpus;
extern crate h2 as http2;
extern crate trust_dns_resolver;
#[macro_use] extern crate actix;

#[cfg(test)]
#[macro_use] extern crate serde_derive;

#[cfg(feature="tls")]
extern crate native_tls;
#[cfg(feature="tls")]
extern crate tokio_tls;

#[cfg(feature="openssl")]
extern crate openssl;
#[cfg(feature="openssl")]
extern crate tokio_openssl;

mod application;
mod body;
mod context;
mod handler;
mod helpers;
mod httpmessage;
mod httprequest;
mod httpresponse;
mod info;
mod json;
mod route;
mod router;
mod resource;
mod param;
mod payload;
mod pipeline;
mod with;
mod extractor;

pub mod client;
pub mod fs;
pub mod ws;
pub mod error;
pub mod header;
pub mod httpcodes;
pub mod multipart;
pub mod middleware;
pub mod pred;
pub mod test;
pub mod server;
pub use error::{Error, Result, ResponseError};
pub use body::{Body, Binary};
pub use json::Json;
pub use application::Application;
pub use httpmessage::HttpMessage;
pub use httprequest::HttpRequest;
pub use httpresponse::HttpResponse;
pub use handler::{Either, Responder, NormalizePath, AsyncResponder, FutureResponse};
pub use route::Route;
pub use resource::Resource;
pub use context::HttpContext;
pub use server::HttpServer;
pub use extractor::{Path, Query};

// re-exports
pub use http::{Method, StatusCode, Version};

#[cfg(feature="openssl")]
pub(crate) const HAS_OPENSSL: bool = true;
#[cfg(not(feature="openssl"))]
pub(crate) const HAS_OPENSSL: bool = false;

#[cfg(feature="tls")]
pub(crate) const HAS_TLS: bool = true;
#[cfg(not(feature="tls"))]
pub(crate) const HAS_TLS: bool = false;

#[doc(hidden)]
#[deprecated(since="0.4.4", note="please use `actix::header` module")]
pub mod headers {
//! Headers implementation

    pub use httpresponse::ConnectionType;
    pub use cookie::{Cookie, CookieBuilder};
    pub use http_range::HttpRange;
    pub use header::ContentEncoding;
}

pub mod dev {
//! The `actix-web` prelude for library developers
//!
//! The purpose of this module is to alleviate imports of many common actix traits
//! by adding a glob import to the top of actix heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use actix_web::dev::*;
//! ```

    pub use body::BodyStream;
    pub use context::Drain;
    pub use info::ConnectionInfo;
    pub use handler::{Handler, Reply};
    pub use with::WithHandler;
    pub use json::JsonBody;
    pub use router::{Router, Pattern};
    pub use param::{FromParam, Params};
    pub use extractor::HttpRequestExtractor;
    pub use httpmessage::{UrlEncoded, MessageBody};
    pub use httpresponse::HttpResponseBuilder;
}
<commit_msg>do not re-export Version<commit_after>//! Actix web is a small, pragmatic, extremely fast, web framework for Rust.
//!
//! ```rust
//! use actix_web::*;
//! # use std::thread;
//!
//! fn index(req: HttpRequest) -> String {
//!     format!("Hello {}!", &req.match_info()["name"])
//! }
//!
//! fn main() {
//! # thread::spawn(|| {
//!     HttpServer::new(
//!         || Application::new()
//!             .resource("/{name}", |r| r.f(index)))
//!         .bind("127.0.0.1:8080").unwrap()
//!         .run();
//! # });
//! }
//! ```
//!
//! ## Documentation
//!
//! * [User Guide](http://actix.github.io/actix-web/guide/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)
//! * Supported Rust version: 1.21 or later
//!
//! ## Features
//!
//! * Supported *HTTP/1.x* and *HTTP/2.0* protocols
//! * Streaming and pipelining
//! * Keep-alive and slow requests handling
//! * `WebSockets` server/client
//! * Transparent content compression/decompression (br, gzip, deflate)
//! * Configurable request routing
//! * Graceful server shutdown
//! * Multipart streams
//! * SSL support with openssl or native-tls
//! * Middlewares (`Logger`, `Session`, `CORS`, `CSRF`, `DefaultHeaders`)
//! * Built on top of [Actix actor framework](https://github.com/actix/actix).

#![cfg_attr(actix_nightly, feature(
    specialization, // for impl ErrorResponse for std::error::Error
))]
#![cfg_attr(feature = "cargo-clippy", allow(
    decimal_literal_representation,suspicious_arithmetic_impl,))]

#[macro_use]
extern crate log;
extern crate time;
extern crate base64;
extern crate bytes;
extern crate byteorder;
extern crate sha1;
extern crate regex;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_io;
extern crate tokio_core;
extern crate mio;
extern crate net2;
extern crate cookie;
extern crate http;
extern crate httparse;
extern crate http_range;
extern crate mime;
extern crate mime_guess;
extern crate language_tags;
extern crate rand;
extern crate url;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate serde_urlencoded;
extern crate flate2;
#[cfg(feature="brotli")]
extern crate brotli2;
extern crate encoding;
extern crate percent_encoding;
extern crate smallvec;
extern crate num_cpus;
extern crate h2 as http2;
extern crate trust_dns_resolver;
#[macro_use] extern crate actix;

#[cfg(test)]
#[macro_use] extern crate serde_derive;

#[cfg(feature="tls")]
extern crate native_tls;
#[cfg(feature="tls")]
extern crate tokio_tls;

#[cfg(feature="openssl")]
extern crate openssl;
#[cfg(feature="openssl")]
extern crate tokio_openssl;

mod application;
mod body;
mod context;
mod handler;
mod helpers;
mod httpmessage;
mod httprequest;
mod httpresponse;
mod info;
mod json;
mod route;
mod router;
mod resource;
mod param;
mod payload;
mod pipeline;
mod with;
mod extractor;

pub mod client;
pub mod fs;
pub mod ws;
pub mod error;
pub mod header;
pub mod httpcodes;
pub mod multipart;
pub mod middleware;
pub mod pred;
pub mod test;
pub mod server;
pub use error::{Error, Result, ResponseError};
pub use body::{Body, Binary};
pub use json::Json;
pub use application::Application;
pub use httpmessage::HttpMessage;
pub use httprequest::HttpRequest;
pub use httpresponse::HttpResponse;
pub use handler::{Either, Responder, NormalizePath, AsyncResponder, FutureResponse};
pub use route::Route;
pub use resource::Resource;
pub use context::HttpContext;
pub use server::HttpServer;
pub use extractor::{Path, Query};

// re-exports
pub use http::{Method, StatusCode};

#[cfg(feature="openssl")]
pub(crate) const HAS_OPENSSL: bool = true;
#[cfg(not(feature="openssl"))]
pub(crate) const HAS_OPENSSL: bool = false;

#[cfg(feature="tls")]
pub(crate) const HAS_TLS: bool = true;
#[cfg(not(feature="tls"))]
pub(crate) const HAS_TLS: bool = false;

#[doc(hidden)]
#[deprecated(since="0.4.4", note="please use `actix::header` module")]
pub mod headers {
//! Headers implementation

    pub use httpresponse::ConnectionType;
    pub use cookie::{Cookie, CookieBuilder};
    pub use http_range::HttpRange;
    pub use header::ContentEncoding;
}

pub mod dev {
//! The `actix-web` prelude for library developers
//!
//! The purpose of this module is to alleviate imports of many common actix traits
//! by adding a glob import to the top of actix heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use actix_web::dev::*;
//! ```

    pub use body::BodyStream;
    pub use context::Drain;
    pub use info::ConnectionInfo;
    pub use handler::{Handler, Reply};
    pub use with::WithHandler;
    pub use json::JsonBody;
    pub use router::{Router, Pattern};
    pub use param::{FromParam, Params};
    pub use extractor::HttpRequestExtractor;
    pub use httpmessage::{UrlEncoded, MessageBody};
    pub use httpresponse::HttpResponseBuilder;
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(asm, core)]
#![feature(libc, page_size)]
#![no_std]

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::{Stack, StackSource};

#[cfg(not(test))]
mod std { pub use core::*; }

pub mod context;
pub mod stack;

mod arch;

#[cfg(feature = "os")]
pub mod os;
<commit_msg>limit compilation of arch to x86_64<commit_after>#![feature(no_std)]
#![feature(asm, core)]
#![feature(libc, page_size)]
#![no_std]

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::{Stack, StackSource};

#[cfg(not(test))]
mod std { pub use core::*; }

pub mod context;
pub mod stack;

#[cfg(target_arch = "x86_64")]
mod arch;

#[cfg(feature = "os")]
pub mod os;
<|endoftext|>