<commit_before>/*!
Simple persistent generic HashMap/Key-value store.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate fs2;

use std::collections::HashMap;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::io::SeekFrom;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

use fs2::FileExt;

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// Macro for what to do on last retry
macro_rules! last_retry {
    ($i:ident, $b:stmt) => (
        if $i >= MAX_RETRIES - 1 {
            $b;
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    /// Cab did not contain anything on disk
    CabEmpty,
    /// Could not decode the cab from disk
    CouldntDecode,
    /// Cab was either not readable from disk or doesn't exist
    DoesntExistOrNotReadable,
    /// Couldn't encode the hashmap for writing to disk
    CouldntEncode,
    /// Could not write to the cab on disk
    CouldntWrite,
    /// Failed to read the cab from disk
    FailedToRead,
    /// Could not flush the data to disk
    CouldntFlush,
    /// Could not open the file from disk
    CouldntOpen,
    /// Could not load the file from disk
    CouldntLoad,
    /// Failed to write lock the cab
    CouldntWriteLock,
    /// Failed to read lock the cab
    CouldntReadLock,
    /// Failed to unlock the cab
    CouldntUnlock,
    /// Failed to set SeekFrom::Start
    CouldntSeekToStart,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p).unwrap(),
        };

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                if e != KVError::CabEmpty {
                    return Err(e);
                }
                warn!("{:?}", e);
            },
        };

        Ok(store)
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> Result<File, KVError> {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return Ok(f); },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntOpen));
                    continue;
                }
            };
        });

        Err(KVError::CouldntOpen)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err(KVError::CouldntEncode);
            },
        };

        // attempt to write to the cab
        retry!(i, {
            // check that can write to the cab
            if let Err(e) = self.file.lock_exclusive() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntWriteLock));
                continue;
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // write the bytes to it
            if let Err(e) = self.file.write_all(byte_vec.as_slice()) {
                error!("file.write_all/retry: {}", e);
                last_retry!(i, return Err(KVError::CouldntWrite));
                continue;
            }

            // flush to disk
            if let Err(e) = self.file.flush() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntFlush));
                continue;
            }
            if let Err(e) = self.file.unlock() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntUnlock));
                continue;
            }
            return Ok(true);
        });

        Err(KVError::CouldntWrite)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if let Err(e) = self.file.lock_shared() {
                error!("{}", e);
                return Err(KVError::CouldntReadLock);
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // read the file into the buffer
            match self.file.read_to_end(&mut byte_vec) {
                Ok(count) => {
                    // don't attempt to decode as empty
                    if count == 0 {
                        if let Err(e) = self.file.unlock() {
                            error!("{}", e);
                            last_retry!(i, return Err(KVError::CouldntUnlock));
                        }
                        return Ok(true);
                    }
                },
                Err(e) => {
                    error!("{}", e);
                    return Err(KVError::FailedToRead);
                },
            }

            // decode u8 vec back into HashMap
            match decode(byte_vec.as_slice()) {
                Ok(f) => {
                    // assign read HashMap back to self
                    self.cab = f;
                    if let Err(e) = self.file.unlock() {
                        error!("{}", e);
                        last_retry!(i, return Err(KVError::CouldntUnlock));
                    }
                    return Ok(true);
                },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntDecode));
                    continue;
                },
            };
        });

        Err(KVError::CouldntLoad)
    }
}
<commit_msg>Cleaned up unused KVError<commit_after>/*!
Simple persistent generic HashMap/Key-value store.

Basic usage:

```
extern crate kv_cab;

use kv_cab::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./db.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get("key".to_string()));
    let _ = test_store.remove("key".to_string());
}
```

Usage with user defined Key and Value types:

```
extern crate kv_cab;
extern crate rustc_serialize;

use kv_cab::KV;

#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
enum MyKey {
    String(String),
    Int(i32),
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
enum MyValue {
    String(String),
    Int(i32),
}

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./db.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(MyKey::Int(1i32)));
    let _ = test_store.remove(MyKey::Int(1i32));
}
```

*/

extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;
extern crate fs2;

use std::collections::HashMap;
use std::fs::{ File, OpenOptions };
use std::io::prelude::*;
use std::io::SeekFrom;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

use fs2::FileExt;

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 10;

/// Definition of a macro for retrying an operation
macro_rules! retry {
    ($i:ident, $b:block) => (
        for $i in 0..MAX_RETRIES {
            if $i != 0 {
                std::thread::park_timeout(std::time::Duration::new(0u64, 1000u32));
            }

            $b
        }
    )
}

/// Macro for what to do on last retry
macro_rules! last_retry {
    ($i:ident, $b:stmt) => (
        if $i >= MAX_RETRIES - 1 {
            $b;
        }
    )
}

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, KVError>;

/// Errors that KV might have
#[derive(Debug, PartialEq)]
pub enum KVError {
    /// Could not decode the cab from disk
    CouldntDecode,
    /// Couldn't encode the hashmap for writing to disk
    CouldntEncode,
    /// Could not write to the cab on disk
    CouldntWrite,
    /// Failed to read the cab from disk
    FailedToRead,
    /// Could not flush the data to disk
    CouldntFlush,
    /// Could not open the file from disk
    CouldntOpen,
    /// Could not load the file from disk
    CouldntLoad,
    /// Failed to write lock the cab
    CouldntWriteLock,
    /// Failed to read lock the cab
    CouldntReadLock,
    /// Failed to unlock the cab
    CouldntUnlock,
    /// Failed to set SeekFrom::Start
    CouldntSeekToStart,
}

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> Result<KV<K,V>, KVError> {
        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: KV::<K, V>::retry_get_file(p).unwrap(),
        };

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                return Err(e);
            },
        };

        Ok(store)
    }

    /// Retry to get a reference to the cab file at path p and create if doesn't exist
    fn retry_get_file(p:&'static str) -> Result<File, KVError> {
        retry!(i, {
            match OpenOptions::new().read(true).write(true).create(true).open(p) {
                Ok(f) => { return Ok(f); },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntOpen));
                    continue;
                }
            };
        });

        Err(KVError::CouldntOpen)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Result<Option<V>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Ok(Some((*v).clone())),
            None => Ok(None),
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist() {
            return Err(e);
        }
        // create a vec from the cabs keys
        Ok(self.cab.keys().map(|k| k.clone()).collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err(KVError::CouldntEncode);
            },
        };

        // attempt to write to the cab
        retry!(i, {
            // check that can write to the cab
            if let Err(e) = self.file.lock_exclusive() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntWriteLock));
                continue;
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // write the bytes to it
            if let Err(e) = self.file.write_all(byte_vec.as_slice()) {
                error!("file.write_all/retry: {}", e);
                last_retry!(i, return Err(KVError::CouldntWrite));
                continue;
            }

            // flush to disk
            if let Err(e) = self.file.flush() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntFlush));
                continue;
            }
            if let Err(e) = self.file.unlock() {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntUnlock));
                continue;
            }
            return Ok(true);
        });

        Err(KVError::CouldntWrite)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if let Err(e) = self.file.lock_shared() {
                error!("{}", e);
                return Err(KVError::CouldntReadLock);
            }

            // seek to the start
            if let Err(e) = self.file.seek(SeekFrom::Start(0)) {
                error!("{}", e);
                last_retry!(i, return Err(KVError::CouldntSeekToStart));
                continue;
            }

            // read the file into the buffer
            match self.file.read_to_end(&mut byte_vec) {
                Ok(count) => {
                    // don't attempt to decode as empty
                    if count == 0 {
                        if let Err(e) = self.file.unlock() {
                            error!("{}", e);
                            last_retry!(i, return Err(KVError::CouldntUnlock));
                        }
                        return Ok(true);
                    }
                },
                Err(e) => {
                    error!("{}", e);
                    return Err(KVError::FailedToRead);
                },
            }

            // decode u8 vec back into HashMap
            match decode(byte_vec.as_slice()) {
                Ok(f) => {
                    // assign read HashMap back to self
                    self.cab = f;
                    if let Err(e) = self.file.unlock() {
                        error!("{}", e);
                        last_retry!(i, return Err(KVError::CouldntUnlock));
                    }
                    return Ok(true);
                },
                Err(e) => {
                    error!("{}", e);
                    last_retry!(i, return Err(KVError::CouldntDecode));
                    continue;
                },
            };
        });

        Err(KVError::CouldntLoad)
    }
}
<|endoftext|>


<commit_before>//! Open URLs in the web browsers available on a platform.
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library.
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux or *bsd => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally.
//!
//! # Examples
//!
//! ```no_run
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```

#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;

use std::default::Default;
use std::io::{Error, ErrorKind, Result};
use std::process::{ExitStatus, Output};
use std::str::FromStr;
use std::{error, fmt};

#[cfg(windows)]
use std::os::windows::process::ExitStatusExt;
#[cfg(windows)]
use std::ptr;

#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;

#[cfg(not(windows))]
use std::process::Command;

#[cfg(windows)]
use widestring::U16CString;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
/// Browser types available
pub enum Browser {
    ///Operating system's default browser
    Default,

    ///Mozilla Firefox
    Firefox,

    ///Microsoft's Internet Explorer
    InternetExplorer,

    ///Google Chrome
    Chrome,

    ///Opera
    Opera,

    ///Mac OS Safari
    Safari,
}

///The Error type for parsing a string into a Browser.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub struct ParseBrowserError;

impl fmt::Display for ParseBrowserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Invalid browser given")
    }
}

impl error::Error for ParseBrowserError {
    fn description(&self) -> &str {
        "invalid browser"
    }
}

impl Default for Browser {
    fn default() -> Self {
        Browser::Default
    }
}

impl fmt::Display for Browser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Browser::Default => f.write_str("Default"),
            Browser::Firefox => f.write_str("Firefox"),
            Browser::InternetExplorer => f.write_str("Internet Explorer"),
            Browser::Chrome => f.write_str("Chrome"),
            Browser::Opera => f.write_str("Opera"),
            Browser::Safari => f.write_str("Safari"),
        }
    }
}

impl FromStr for Browser {
    type Err = ParseBrowserError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        match s {
            "firefox" => Ok(Browser::Firefox),
            "default" => Ok(Browser::Default),
            "ie" | "internet explorer" | "internetexplorer" => Ok(Browser::InternetExplorer),
            "chrome" => Ok(Browser::Chrome),
            "opera" => Ok(Browser::Opera),
            "safari" => Ok(Browser::Safari),
            _ => Err(ParseBrowserError),
        }
    }
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found.
///
/// Equivalent to:
/// ```no_run
/// # use webbrowser::{Browser, open_browser};
/// # let url = "http://example.com";
/// open_browser(Browser::Default, url);
/// ```
///
/// # Examples
/// ```no_run
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html).
///
/// # Examples
/// ```no_run
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    open_browser_internal(browser, url).and_then(|status| {
        if let Some(code) = status.code() {
            if code == 0 {
                Ok(Output {
                    status: ExitStatus::from_raw(0),
                    stdout: vec![],
                    stderr: vec![],
                })
            } else {
                Err(Error::new(
                    ErrorKind::Other,
                    format!("return code {}", code),
                ))
            }
        } else {
            Err(Error::new(ErrorKind::Other, "interrupted by signal"))
        }
    })
}

/// Deal with opening of browsers on Windows, using [`ShellExecuteW`](
/// https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecutew)
/// fucntion.
#[cfg(target_os = "windows")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    use winapi::shared::winerror::SUCCEEDED;
    use winapi::um::combaseapi::{CoInitializeEx, CoUninitialize};
    use winapi::um::objbase::{COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE};
    use winapi::um::shellapi::ShellExecuteW;
    use winapi::um::winuser::SW_SHOWNORMAL;
    match browser {
        Browser::Default => {
            static OPEN: &[u16] = &['o' as u16, 'p' as u16, 'e' as u16, 'n' as u16, 0x0000];
            let url =
                U16CString::from_str(url).map_err(|e| Error::new(ErrorKind::InvalidInput, e))?;
            let code = unsafe {
                let coinitializeex_result = CoInitializeEx(
                    ptr::null_mut(),
                    COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE,
                );
                let code = ShellExecuteW(
                    ptr::null_mut(),
                    OPEN.as_ptr(),
                    url.as_ptr(),
                    ptr::null(),
                    ptr::null(),
                    SW_SHOWNORMAL,
                ) as usize as i32;
                if SUCCEEDED(coinitializeex_result) {
                    CoUninitialize();
                }
                code
            };
            if code > 32 {
                Ok(ExitStatus::from_raw(0))
            } else {
                Err(Error::last_os_error())
            }
        }
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).status(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None,
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).status(),
                None => Err(Error::new(
                    ErrorKind::NotFound,
                    format!("Unsupported browser {:?}", browser),
                )),
            }
        }
    }
}

/// Deal with opening of browsers on Linux and *BSD - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    match browser {
        Browser::Default => open_on_unix_using_browser_env(url)
            .or_else(|_| -> Result<ExitStatus> { Command::new("xdg-open").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("gvfs-open").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("gnome-open").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("kioclient").arg("exec").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("x-www-browser").arg(url).status() }),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}
#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
fn open_on_unix_using_browser_env(url: &str) -> Result<ExitStatus> {
    let browsers = ::std::env::var("BROWSER")
        .map_err(|_| -> Error { Error::new(ErrorKind::NotFound, "BROWSER env not set") })?;
    for browser in browsers.split(':') {
        // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser
                .replace("%s", url)
                .replace("%c", ":")
                .replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(status) = cmd.status() {
                return Ok(status);
            }
        }
    }
    Err(Error::new(
        ErrorKind::NotFound,
        "No valid command in $BROWSER",
    ))
}

#[cfg(not(any(
    target_os = "windows",
    target_os = "macos",
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
)))]
compile_error!("Only Windows, Mac OS, Linux and *BSD are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
    assert!(open("http://github.com?dummy_query1=0&dummy_query2=ｎｏｎａｓｃｉｉ").is_ok());
}

#[test]
#[ignore]
fn test_open_firefox() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}

#[test]
#[ignore]
fn test_open_chrome() {
    assert!(open_browser(Browser::Chrome, "http://github.com").is_ok());
}

#[test]
#[ignore]
#[cfg(target_os = "windows")]
fn test_open_internet_explorer() {
    assert!(open_browser(Browser::InternetExplorer, "http://github.com").is_ok());
}

#[test]
#[ignore]
fn test_open_safari() {
    assert!(open_browser(Browser::Safari, "http://github.com").is_ok());
}
<commit_msg>Under KDE, let kioclient take precendence over gvfs-open<commit_after>//! Open URLs in the web browsers available on a platform.
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library.
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux or *bsd => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally.
//!
//! # Examples
//!
//! ```no_run
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```

#[cfg(windows)]
extern crate widestring;
#[cfg(windows)]
extern crate winapi;

use std::default::Default;
use std::io::{Error, ErrorKind, Result};
use std::process::{ExitStatus, Output};
use std::str::FromStr;
use std::{error, fmt};

#[cfg(windows)]
use std::os::windows::process::ExitStatusExt;
#[cfg(windows)]
use std::ptr;

#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;

#[cfg(not(windows))]
use std::process::Command;

#[cfg(windows)]
use widestring::U16CString;

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
/// Browser types available
pub enum Browser {
    ///Operating system's default browser
    Default,

    ///Mozilla Firefox
    Firefox,

    ///Microsoft's Internet Explorer
    InternetExplorer,

    ///Google Chrome
    Chrome,

    ///Opera
    Opera,

    ///Mac OS Safari
    Safari,
}

///The Error type for parsing a string into a Browser.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub struct ParseBrowserError;

impl fmt::Display for ParseBrowserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Invalid browser given")
    }
}

impl error::Error for ParseBrowserError {
    fn description(&self) -> &str {
        "invalid browser"
    }
}

impl Default for Browser {
    fn default() -> Self {
        Browser::Default
    }
}

impl fmt::Display for Browser {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Browser::Default => f.write_str("Default"),
            Browser::Firefox => f.write_str("Firefox"),
            Browser::InternetExplorer => f.write_str("Internet Explorer"),
            Browser::Chrome => f.write_str("Chrome"),
            Browser::Opera => f.write_str("Opera"),
            Browser::Safari => f.write_str("Safari"),
        }
    }
}

impl FromStr for Browser {
    type Err = ParseBrowserError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        match s {
            "firefox" => Ok(Browser::Firefox),
            "default" => Ok(Browser::Default),
            "ie" | "internet explorer" | "internetexplorer" => Ok(Browser::InternetExplorer),
            "chrome" => Ok(Browser::Chrome),
            "opera" => Ok(Browser::Opera),
            "safari" => Ok(Browser::Safari),
            _ => Err(ParseBrowserError),
        }
    }
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found.
///
/// Equivalent to:
/// ```no_run
/// # use webbrowser::{Browser, open_browser};
/// # let url = "http://example.com";
/// open_browser(Browser::Default, url);
/// ```
///
/// # Examples
/// ```no_run
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html).
///
/// # Examples
/// ```no_run
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    open_browser_internal(browser, url).and_then(|status| {
        if let Some(code) = status.code() {
            if code == 0 {
                Ok(Output {
                    status: ExitStatus::from_raw(0),
                    stdout: vec![],
                    stderr: vec![],
                })
            } else {
                Err(Error::new(
                    ErrorKind::Other,
                    format!("return code {}", code),
                ))
            }
        } else {
            Err(Error::new(ErrorKind::Other, "interrupted by signal"))
        }
    })
}

/// Deal with opening of browsers on Windows, using [`ShellExecuteW`](
/// https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecutew)
/// fucntion.
#[cfg(target_os = "windows")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    use winapi::shared::winerror::SUCCEEDED;
    use winapi::um::combaseapi::{CoInitializeEx, CoUninitialize};
    use winapi::um::objbase::{COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE};
    use winapi::um::shellapi::ShellExecuteW;
    use winapi::um::winuser::SW_SHOWNORMAL;
    match browser {
        Browser::Default => {
            static OPEN: &[u16] = &['o' as u16, 'p' as u16, 'e' as u16, 'n' as u16, 0x0000];
            let url =
                U16CString::from_str(url).map_err(|e| Error::new(ErrorKind::InvalidInput, e))?;
            let code = unsafe {
                let coinitializeex_result = CoInitializeEx(
                    ptr::null_mut(),
                    COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE,
                );
                let code = ShellExecuteW(
                    ptr::null_mut(),
                    OPEN.as_ptr(),
                    url.as_ptr(),
                    ptr::null(),
                    ptr::null(),
                    SW_SHOWNORMAL,
                ) as usize as i32;
                if SUCCEEDED(coinitializeex_result) {
                    CoUninitialize();
                }
                code
            };
            if code > 32 {
                Ok(ExitStatus::from_raw(0))
            } else {
                Err(Error::last_os_error())
            }
        }
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).status(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None,
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).status(),
                None => Err(Error::new(
                    ErrorKind::NotFound,
                    format!("Unsupported browser {:?}", browser),
                )),
            }
        }
    }
}

/// Deal with opening of browsers on Linux and *BSD - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<ExitStatus> {
    match browser {
        Browser::Default => open_on_unix_using_browser_env(url)
            .or_else(|_| -> Result<ExitStatus> { Command::new("xdg-open").arg(url).status() })
            .or_else(|r| -> Result<ExitStatus> {
                if let Ok(desktop) = ::std::env::var("XDG_CURRENT_DESKTOP") {
                    if desktop == "KDE" {
                        return Command::new("kioclient").arg("exec").arg(url).status()
                    }
                }
                Err(r)  // If either `if` check fails, fall through to the next or_else
            }).or_else(|_| -> Result<ExitStatus> { Command::new("gvfs-open").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("gnome-open").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("kioclient").arg("exec").arg(url).status() })
            .or_else(|_| -> Result<ExitStatus> { Command::new("x-www-browser").arg(url).status() }),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now",
        )),
    }
}
#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
fn open_on_unix_using_browser_env(url: &str) -> Result<ExitStatus> {
    let browsers = ::std::env::var("BROWSER")
        .map_err(|_| -> Error { Error::new(ErrorKind::NotFound, "BROWSER env not set") })?;
    for browser in browsers.split(':') {
        // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser
                .replace("%s", url)
                .replace("%c", ":")
                .replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(status) = cmd.status() {
                return Ok(status);
            }
        }
    }
    Err(Error::new(
        ErrorKind::NotFound,
        "No valid command in $BROWSER",
    ))
}

#[cfg(not(any(
    target_os = "windows",
    target_os = "macos",
    target_os = "linux",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
)))]
compile_error!("Only Windows, Mac OS, Linux and *BSD are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
    assert!(open("http://github.com?dummy_query1=0&dummy_query2=ｎｏｎａｓｃｉｉ").is_ok());
}

#[test]
#[ignore]
fn test_open_firefox() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}

#[test]
#[ignore]
fn test_open_chrome() {
    assert!(open_browser(Browser::Chrome, "http://github.com").is_ok());
}

#[test]
#[ignore]
#[cfg(target_os = "windows")]
fn test_open_internet_explorer() {
    assert!(open_browser(Browser::InternetExplorer, "http://github.com").is_ok());
}

#[test]
#[ignore]
fn test_open_safari() {
    assert!(open_browser(Browser::Safari, "http://github.com").is_ok());
}
<|endoftext|>


<commit_before>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x <= HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x <= HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x <= HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x <= HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x <= HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x <= HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x <= HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x <= HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x <= HAND_RANK_COUNT-0    => HandRankClass::StraightFlush,
        _                              => panic!("Unexpected hand rank value!")
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<commit_msg>The hell did I do there.<commit_after>extern crate cards;

use std::cmp::{Ord};

use cards::card::{Card};

#[derive(Debug, PartialEq)]
#[derive(Eq, Hash)]
#[derive(PartialOrd, Ord)]
pub enum HandRankClass {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

// find maximum value to determine best hand
// larger values are "better", inverting the Cactus Kev convention
pub type HandRank = u16;

pub const HAND_RANK_COUNT : u16 = 7462;

// assumes there are HAND_RANK_COUNT distinct hand ranks, where the
// largest are the most valuable. An inversion of cactus kev's ranks.
pub fn hand_rank_to_class(val: &HandRank) -> HandRankClass {
    match *val {
        x if x < HAND_RANK_COUNT-6185 => HandRankClass::HighCard,
        x if x < HAND_RANK_COUNT-3325 => HandRankClass::OnePair,
        x if x < HAND_RANK_COUNT-2467 => HandRankClass::TwoPair,
        x if x < HAND_RANK_COUNT-1609 => HandRankClass::ThreeOfAKind,
        x if x < HAND_RANK_COUNT-1599 => HandRankClass::Straight,
        x if x < HAND_RANK_COUNT-322  => HandRankClass::Flush,
        x if x < HAND_RANK_COUNT-166  => HandRankClass::FullHouse,
        x if x < HAND_RANK_COUNT-10   => HandRankClass::FourOfAKind,
        x if x < HAND_RANK_COUNT-0    => HandRankClass::StraightFlush,
        x                             => panic!("Unexpected hand rank value! '{}'", x)
    }
}

pub enum CardSlot {
    Empty,
    Dealt(Card),
}

impl CardSlot {
    pub fn expect_borrow(&self) -> &Card {
        match self {
            &CardSlot::Empty => panic!("You are trying to borrow a non-dealt card"),
            &CardSlot::Dealt(ref x) => x
        }
    }
}

pub struct HandCards(pub CardSlot, pub CardSlot);
pub struct CommunityCards(pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot, pub CardSlot);
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use context::AContext;
    pub use context::ext::*;
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use framebuffer::{FramebufferContext, ContextFramebufferBuilderExt};
    pub use program::{ProgramContext, ContextProgramBuilderExt};
    pub use renderbuffer::{RenderbufferContext, ContextRenderbufferBuilderExt};
    pub use shader::ContextShaderBuilderExt;
    pub use texture_units::{TextureUnit,
                            TextureUnit0Context, TextureUnit1Context,
                            TextureUnit2Context, TextureUnit3Context,
                            TextureUnit4Context, TextureUnit5Context,
                            TextureUnit6Context, TextureUnit7Context};
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext,
                            ContextVertexBufferExt};
}
<commit_msg>Add `TextureUnitBindingOf` struct, aliases, and traits to the prelude<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use context::AContext;
    pub use context::ext::*;
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use framebuffer::{FramebufferContext, ContextFramebufferBuilderExt};
    pub use program::{ProgramContext, ContextProgramBuilderExt};
    pub use renderbuffer::{RenderbufferContext, ContextRenderbufferBuilderExt};
    pub use shader::ContextShaderBuilderExt;
    pub use texture_units::{TextureUnit, TextureUnitBinding,
                            TextureUnitBindingOf, ATextureUnitBinding,
                            TextureUnitBinding2d, TextureUnitBindingCubeMap,
                            TextureUnit0Context, TextureUnit1Context,
                            TextureUnit2Context, TextureUnit3Context,
                            TextureUnit4Context, TextureUnit5Context,
                            TextureUnit6Context, TextureUnit7Context};
    pub use texture::TextureBinding;
    pub use vertex_buffer::{VertexBufferContext, IndexBufferContext,
                            ContextVertexBufferExt};
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
extern crate usb;
extern crate serialize;

use serialize::{Encoder, Encodable, Decoder, Decodable};
use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, FormatError};
use usb::libusb;

#[deriving(Show)]
pub enum AnalogChannel {
    A1,
    A2
}

#[deriving(Show)]
pub enum DigitalChannel {
    D1 = 1,
    D2 = 2,
    D3 = 4,
    D4 = 8,
    D5 = 16,
    D6 = 32,
    D7 = 64,
    D8 = 128
}

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8)
}

impl<E: Encoder<S>, S> Encodable<E, S> for Packet {
  fn encode(&self, e: &mut E) -> Result<(), S> {
      match *self {
          Reset => [0u8, ..8].encode(e),
          SetAnalogDigital(dig, ana1, ana2) => [5u8, dig, ana1, ana2,
                                                0u8, 0u8, 0u8, 0u8].encode(e),
          _ => fail!("Unknown cmd")
      }
  }
}

impl<E, D: Decoder<E>> Decodable<D, E> for Packet {
    fn decode(d: &mut D) -> Result<Packet, E> {
        let bytes: Vec<u8> = try!(Decodable::decode(d));
        Ok(Status(0u8))
    }
}

pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>

}

impl K8055 {
    pub fn new() -> Option<K8055> {
        let c = usb::Context::new();
        let d = K8055::find_k8055(&c);
        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None })
        } else {
            return None
        }
    }

    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(e) => return false
      }
    }

    fn find_k8055(c: &usb::Context) -> Option<usb::Device> {
        let vid = 0x10cfu;
        for pid in range_inclusive(0x5500, 0x5503) {
          let d = c.find_by_vid_pid(vid, pid);
          if d.is_some() { return d }
        }
        None
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
}

<commit_msg>Add write function<commit_after>#![crate_type = "lib"]
extern crate libc;
extern crate usb;
extern crate serialize;

use std::io::timer::sleep;
use std::iter::range_inclusive;
use std::fmt::{Show, Formatter, FormatError};
use usb::libusb;

bitflags!(
  flags AnalogChannel: u8 {
      static A1 = 1,
      static A2 = 2
  }
)

bitflags!(
  flags DigitalChannel: u8 {
    static D1 = 1,
    static D2 = 2,
    static D3 = 4,
    static D4 = 8,
    static D5 = 16,
    static D6 = 32,
    static D7 = 64,
    static D8 = 128
  }
)

#[deriving(Show)]
enum Packet {
    Reset,
    SetAnalogDigital(u8, u8, u8),
    Status(u8)
}

pub struct K8055 {
    dev: usb::Device,
    hd: Option<usb::DeviceHandle>

}

impl K8055 {
    pub fn new() -> Option<K8055> {
        let c = usb::Context::new();
        let d = K8055::find_k8055(&c);
        if d.is_some() {
            return Some(K8055{ dev: d.unwrap(), hd: None })
        } else {
            return None
        }
    }

    pub fn open(&mut self) -> bool {
      // device already open
      if self.hd.is_some() { return true }
      match self.dev.open() {
          Ok(h) => {
              self.hd = Some(h);
              return true
          }
          Err(e) => return false
      }
    }

    fn find_k8055(c: &usb::Context) -> Option<usb::Device> {
        let vid = 0x10cfu;
        for pid in range_inclusive(0x5500, 0x5503) {
          let d = c.find_by_vid_pid(vid, pid);
          if d.is_some() { return d }
        }
        None
    }

    fn write(&mut self, p: &Packet) -> bool {
        match self.hd {
          Some(ref hd) => {
              unsafe {
                  if libusb::libusb_kernel_driver_active(hd.ptr(), 0) == 1 {
                      if libusb::libusb_detach_kernel_driver(hd.ptr(), 0) != 0 {
                          fail!("Can't detach usb kernel driver");
                      }
                  }
              }
              hd.claim_interface(0u);
              let data = match K8055::encode(p) {
                  Some(d) => d,
                  None => return false
              };

              match hd.write(0x1, libusb::LIBUSB_TRANSFER_TYPE_INTERRUPT, data) {
                  Ok(_) => return true,
                  Err(_) => return false
              }
          }
          None => return false
        }
    }

    fn encode(p: &Packet) -> Option<[u8, ..8]> {
      match *p {
          Reset => Some([0u8, ..8]),
          SetAnalogDigital(dig, ana1, ana2) => Some([5u8, dig, ana1, ana2,
                                                     0u8, 0u8, 0u8, 0u8]),
          _ => None
      }
    }

    fn decode(d: &[u8, ..8]) -> Option<Packet> {
        //let bytes: Vec<u8> = try!(Decodable::decode(d));
        Some(Status(0u8))
    }

}

impl Show for K8055 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
      write!(f, "K8055( bus: {}, address: {} )", self.dev.bus(), self.dev.address())
    }
}

#[test()]
fn find_and_open() {
  let k = K8055::new();
  assert!(k.is_some());
  let mut k = k.unwrap();
  assert!(k.open());
  for i in range(0u8, 255) {
    assert!(k.write(&SetAnalogDigital(i, 0u8, 0u8)));
    sleep(100);
  }

  assert!(k.write(&SetAnalogDigital(0u8, 0u8, 0u8)));
}

<|endoftext|>


<commit_before>//! oppgave - A simple Redis-based task queue
//!
//!
//! ## Example: Producer
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let producer = Queue::new("default".into(), con);
//!
//! producer.push(Job{ id: 42 });
//! ```
//!
//! ## Example: Worker
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let worker = Queue::new("default".into(), con);
//!
//! while let Some(task) = worker.next() {
//!     println!("Working with Job {}", job.id);
//! }
//! ```

#![deny(missing_docs)]

extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the JSON stored in Redis
///
/// Implemented for all `Decodable` objects by default.
pub trait TaskDecodable where Self: Sized {
    /// Decode the given Redis value into a task
    ///
    /// This should decode the string value into a proper task.
    /// The string value is encoded as JSON.
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to JSON to be stored in Redis
///
/// Implemented for all `Encodable` objects by default.
pub trait TaskEncodable {
    /// Encode the value into a Blob to insert into Redis
    ///
    /// It should encode the value into a JSON string.
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    queue: &'a Queue,
    failed: Cell<bool>,
}

impl<'a, T> TaskGuard<'a, T> {
    /// Stop the underlying queue
    pub fn stop(&self) {
        self.queue.stop();
    }

    /// Fail the current task and don't remove it from the backup queue
    pub fn fail(&self) {
        self.failed.set(true);
    }

    /// Get access to the underlying task
    pub fn inner(&self) -> &T {
        &self.task
    }

    /// Get access to the wrapper queue
    pub fn queue(&self) -> &Queue {
        self.queue
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        if !self.failed.get() {
            // Pop job from backup queue
            let backup = &self.queue.backup_queue[..];
            let _ : () = self.queue.client.lpop(backup).expect("LPOP from backup queue failed");
        }
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, queue: self, failed: Cell::new(false)}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::*;

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueue() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53});

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }

    #[test]
    fn does_not_drop_failed() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("failure".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.del(worker.backup_queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();

        {
            let task : TaskGuard<Job> = worker.next().unwrap().unwrap();
            task.fail();
        }

        let len : u32 = con.llen(worker.backup_queue()).unwrap();
        assert_eq!(1, len);
    }
}
<commit_msg>fix: Explicit super imports<commit_after>//! oppgave - A simple Redis-based task queue
//!
//!
//! ## Example: Producer
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let producer = Queue::new("default".into(), con);
//!
//! producer.push(Job{ id: 42 });
//! ```
//!
//! ## Example: Worker
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let worker = Queue::new("default".into(), con);
//!
//! while let Some(task) = worker.next() {
//!     println!("Working with Job {}", job.id);
//! }
//! ```

#![deny(missing_docs)]

extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the JSON stored in Redis
///
/// Implemented for all `Decodable` objects by default.
pub trait TaskDecodable where Self: Sized {
    /// Decode the given Redis value into a task
    ///
    /// This should decode the string value into a proper task.
    /// The string value is encoded as JSON.
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to JSON to be stored in Redis
///
/// Implemented for all `Encodable` objects by default.
pub trait TaskEncodable {
    /// Encode the value into a Blob to insert into Redis
    ///
    /// It should encode the value into a JSON string.
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    queue: &'a Queue,
    failed: Cell<bool>,
}

impl<'a, T> TaskGuard<'a, T> {
    /// Stop the underlying queue
    pub fn stop(&self) {
        self.queue.stop();
    }

    /// Fail the current task and don't remove it from the backup queue
    pub fn fail(&self) {
        self.failed.set(true);
    }

    /// Get access to the underlying task
    pub fn inner(&self) -> &T {
        &self.task
    }

    /// Get access to the wrapper queue
    pub fn queue(&self) -> &Queue {
        self.queue
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        if !self.failed.get() {
            // Pop job from backup queue
            let backup = &self.queue.backup_queue[..];
            let _ : () = self.queue.client.lpop(backup).expect("LPOP from backup queue failed");
        }
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, queue: self, failed: Cell::new(false)}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::{Queue, TaskGuard};

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueue() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53});

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }

    #[test]
    fn does_not_drop_failed() {
        let client = redis::Client::open("redis://127.0.0.1:6380/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("failure".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.del(worker.backup_queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();

        {
            let task : TaskGuard<Job> = worker.next().unwrap().unwrap();
            task.fail();
        }

        let len : u32 = con.llen(worker.backup_queue()).unwrap();
        assert_eq!(1, len);
    }
}
<|endoftext|>


<commit_before>mod ffi;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt: i32 = unsafe { ffi::soundio_backend_count(self.context) };
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
}
<commit_msg>Add test for enums<commit_after>mod ffi;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt: i32 = unsafe { ffi::soundio_backend_count(self.context) };
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
}

#[test]
fn test_enums() {
    assert_eq!("(no error)",
               format!("{}", ffi::Enum_SoundIoError::SoundIoErrorNone));
    assert_eq!("ALSA",
               format!("{}", ffi::Enum_SoundIoBackend::SoundIoBackendAlsa));
}
<|endoftext|>


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

#[macro_use]
extern crate core;

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

pub use context::Context;

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

mod context;
mod stack;

mod arch;
mod platform;
<commit_msg>no_std is a feature flag now<commit_after>#![feature(no_std)]
#![feature(asm, core)]
#![feature(os, libc)]
#![no_std]

#[macro_use]
extern crate core;

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

pub use context::Context;

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

mod context;
mod stack;

mod arch;
mod platform;
<|endoftext|>


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

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.

extern crate bincode;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::SizeLimit;
use bincode::serde::serialize as bin_serialize;
use serde_json::{to_string as json_serialize, from_str as json_deserialize, error as json};

pub use real_error_impls::RealError;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Clone, Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

impl Display for SeralizableError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => write!(fmt, "{}", perr),
        }
    }
}

impl<'a> From<&'a Error> for SeralizableError {
    fn from(err: &Error) -> SeralizableError {
        // TODO: Check if can be seralized as RealError.
        SeralizableError::PseudoError(PseudoError::from(err))
    }
}

impl Error for SeralizableError {
    fn description(&self) -> &str {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.description(),
        }
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.cause(),
        }
    }
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Clone, Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_owned(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
pub fn serialize_error_bytes(to_ser: &Error) -> Vec<u8> {
    bin_serialize(&SeralizableError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
pub fn serialize_error_string(to_ser: &Error) -> String {
    json_serialize(&SeralizableError::from(to_ser)).unwrap()
}

/// Deseralizes a string to a SeralizableError.
pub fn deserialize_error_string(to_de: &str) -> Result<SeralizableError, json::Error> {
    json_deserialize(to_de)
}

#[cfg(test)]
mod test {
    #[test]
    fn serialize_error_bytes() {}
}
<commit_msg>Adds a a helper method for deserializing byte slices<commit_after>#![feature(custom_derive, plugin)]
#![plugin(serde_macros, clippy)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces, unused_qualifications,
        warnings, clippy)]

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.

extern crate bincode;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::{SizeLimit, serde as bin};
use bincode::serde::{serialize as bin_serialize, deserialize as bin_deserialize};
use serde_json::{to_string as json_serialize, from_str as json_deserialize, error as json};

pub use real_error_impls::RealError;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Clone, Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

impl Display for SeralizableError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => write!(fmt, "{}", perr),
        }
    }
}

impl<'a> From<&'a Error> for SeralizableError {
    fn from(err: &Error) -> SeralizableError {
        // TODO: Check if can be seralized as RealError.
        SeralizableError::PseudoError(PseudoError::from(err))
    }
}

impl Error for SeralizableError {
    fn description(&self) -> &str {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.description(),
        }
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.cause(),
        }
    }
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Clone, Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_owned(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
pub fn serialize_error_bytes(to_ser: &Error) -> Vec<u8> {
    bin_serialize(&SeralizableError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
pub fn serialize_error_string(to_ser: &Error) -> String {
    json_serialize(&SeralizableError::from(to_ser)).unwrap()
}

/// Deseralizes a slice of bytes into a SeralizableError.
pub fn deserialize_error_bytes(to_de: &[u8]) -> Result<SeralizableError, bin::DeserializeError> {
    bin_deserialize(to_de)
}

/// Deseralizes a string to a SeralizableError.
pub fn deserialize_error_string(to_de: &str) -> Result<SeralizableError, json::Error> {
    json_deserialize(to_de)
}

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