<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));
}
```

*/

#![deny(missing_docs)]

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 {
    /// Cab type for strings
    String(String),
    /// Cab type for intergers
    Int(i32),
    /// Cab type for floats
    Float(f32),
    /// Cab type for a sub map
    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(false) {
            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 {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            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(false) {
            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 {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            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(false) {
            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 {
        // 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;
            }

            // 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);
                },
            };

            // 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;
            }

            // unlock the file after write has completed
            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, already_locked:bool) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if !already_locked {
                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 !already_locked {
                            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 !already_locked {
                        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>Added a default value type for a list<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));
}
```

*/

#![deny(missing_docs)]

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 {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<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(false) {
            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 {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            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(false) {
            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 {
        // check that can write to the cab
        if let Err(e) = self.file.lock_exclusive() {
            error!("{}", e);
            return Err(KVError::CouldntWriteLock);
        }
        // make sure mem version up to date
        if let Err(e) = self.load_from_persist(true) {
            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(false) {
            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 {
        // 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;
            }

            // 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);
                },
            };

            // 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;
            }

            // unlock the file after write has completed
            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, already_locked:bool) -> KVResult {
        retry!(i, {
            // byte vec to read into
            let mut byte_vec = Vec::new();

            // wait/lock the cab and read the bytes
            if !already_locked {
                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 !already_locked {
                            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 !already_locked {
                        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>use std::collections::HashMap;

pub struct Keypad {
    layout: HashMap<u8, Key>,
    current_value: u8,
}

impl Keypad {
    fn new() -> Keypad {
        let mut layout = HashMap::new();

        layout.insert(1, Key {
           value: 1,
           left: None,
           up: None,
           right: Some(2),
           down: Some(4),
        });

        layout.insert(2, Key {
           value: 2,
           left: Some(1),
           up: None,
           right: Some(3),
           down: Some(5),
        });

        layout.insert(3, Key {
           value: 3,
           left: Some(2),
           up: None,
           right: None,
           down: Some(6),
        });

        layout.insert(4, Key {
           value: 4,
           left: None,
           up: Some(1),
           right: Some(5),
           down: Some(7),
        });

        layout.insert(5, Key {
           value: 5,
           left: Some(4),
           up: Some(2),
           right: Some(6),
           down: Some(8),
        });

        layout.insert(6, Key {
           value: 6,
           left: Some(5),
           up: Some(3),
           right: None,
           down: Some(9),
        });

        layout.insert(7, Key {
           value: 7,
           left: None,
           up: Some(4),
           right: Some(8),
           down: None,
        });

        layout.insert(8, Key {
           value: 8,
           left: Some(7),
           up: Some(5),
           right: Some(9),
           down: None,
        });

        layout.insert(9, Key {
           value: 9,
           left: Some(8),
           up: Some(6),
           right: None,
           down: None,
        });

        Keypad {
            layout: layout,
            current_value: 5,
        }
    }

    fn move_a_key(&mut self, instruction: char) {
        let current_key = self.layout.get(&self.current_value)
                                     .expect("impossible missing key");

        let next_key_value = match instruction {
            'U' => current_key.up.unwrap_or(current_key.value),
            'D' => current_key.down.unwrap_or(current_key.value),
            'L' => current_key.left.unwrap_or(current_key.value),
            'R' => current_key.right.unwrap_or(current_key.value),
            other => panic!("Don't know how to move ({})!", other),
        };

        self.current_value = next_key_value;
    }
}

struct Key {
    value: u8,
    left: Option<u8>,
    right: Option<u8>,
    up: Option<u8>,
    down: Option<u8>,
}

pub fn puzzle(input: &str) -> String {
    let mut keypad = Keypad::new();
    let mut answer = String::new();

    for line in input.lines() {
        for c in line.chars() {
            keypad.move_a_key(c);
        }
        answer.push_str(&format!("{}", keypad.current_value));
    }
    answer
}

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

    #[test]
    fn regular_move() {
        let mut keypad = Keypad::new();

        keypad.move_a_key('U');
        assert_eq!(keypad.current_value, 2);
    }

    #[test]
    fn ignored_move() {
        let mut keypad = Keypad::new();

        keypad.move_a_key('U');
        keypad.move_a_key('U');
        assert_eq!(keypad.current_value, 2);
    }

    #[test]
    fn overall_puzzle() {
        let input = "ULL\nRRDDD\nLURDL\nUUUUD\n";
        let answer = puzzle(input);
        assert_eq!(String::from("1985"), answer);
    }
}
<commit_msg>Change how Keypad is implemented<commit_after>pub struct Keypad {
    width: usize,
    height: usize,
    layout: Vec<Vec<char>>,
    x: usize,
    y: usize,
}

impl Keypad {
    fn new(layout_description: &str) -> Keypad {
        let layout: Vec<Vec<char>> = layout_description
                         .lines()
                         .map(|line| line.chars().collect::<Vec<_>>() )
                         .collect();

        let mut x = 0;
        let mut y = 0;

        for (yi, yval) in layout.iter().enumerate() {
            for (xi, &xval) in yval.iter().enumerate() {
                if xval == '5' {
                    x = xi;
                    y = yi;
                    break;
                }
            }
        }

        Keypad {
            width: layout[0].len(),
            height: layout.len(),
            layout: layout,
            x: x,
            y: y,
        }
    }

    fn current_value(&self) -> char {
        self.layout[self.y][self.x]
    }
}

pub fn puzzle(input: &str) -> String {
    let mut keypad = Keypad::new("1");
    let mut answer = String::new();

    answer
}

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

    #[test]
    fn small_keypad_construction() {
        let keypad = Keypad::new("1");
        assert_eq!(keypad.width, 1);
        assert_eq!(keypad.height, 1);
        assert_eq!(keypad.current_value(), '1');
    }

    #[test]
    fn tall_keypad_construction() {
        let keypad = Keypad::new("1\n2\n3");
        assert_eq!(keypad.width, 1);
        assert_eq!(keypad.height, 3);
        assert_eq!(keypad.current_value(), '1');
    }

    #[test]
    fn desired_keypad_construction() {
        let keypad = Keypad::new("123\n456\n789");
        assert_eq!(keypad.width, 3);
        assert_eq!(keypad.height, 3);
        assert_eq!(keypad.current_value(), '5');
    }
}
<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     }).detach();
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

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

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::kinds::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, INIT_STATIC_SPINLOCK};
///
/// static SPLCK: StaticSpinlock = INIT_STATIC_SPINLOCK;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<commit_msg>Rename INIT_STATIC_SPINLOCK just as atomic bool<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     }).detach();
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

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

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::kinds::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      {format!("{} B", self.size)}
    } else {
      let exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;

      if si {
        format!("{} {}iB",(self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B",(self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

#[test]
fn test_arithmetic() {
  let x = ByteSize::mb(1);
  let y = ByteSize::kb(100);

  assert_eq!(
    (x + y).as_usize(),
    1100000
  );
  assert_eq!(
    (x + (100*1000)).as_usize(),
    1100000
  );

  assert_eq!(
    (x - y).as_usize(),
    900000
  );
  assert_eq!(
    (x - (100*1000)).as_usize(),
    900000
  );
}

#[allow(dead_code)]
fn assert_display(expected: &str, b: ByteSize) {
  assert_eq!(expected, format!("{}", b));
}

#[test]
fn test_display() {
  assert_display("215 B", ByteSize::b(215));
  assert_display("301 KB", ByteSize::kb(301));
  assert_display("419 MB", ByteSize::mb(419));
  assert_display("518 GB", ByteSize::gb(518));
  assert_display("815 TB", ByteSize::tb(815));
  assert_display("609 PB", ByteSize::pb(609));
}

#[allow(dead_code)]
fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
  assert_eq!(expected.to_string(), b.to_string(si));
}

#[test]
fn test_to_string() {
  assert_to_string("215 B", ByteSize::b(215), true);
  assert_to_string("215 B", ByteSize::b(215), false);

  assert_to_string("293 kiB", ByteSize::kb(301), true);
  assert_to_string("301 KB", ByteSize::kb(301), false);

  assert_to_string("399 MiB", ByteSize::mb(419), true);
  assert_to_string("419 MB", ByteSize::mb(419), false);

  assert_to_string("482 GiB", ByteSize::gb(518), true);
  assert_to_string("518 GB", ByteSize::gb(518), false);

  assert_to_string("741 TiB", ByteSize::tb(815), true);
  assert_to_string("815 TB", ByteSize::tb(815), false);

  assert_to_string("540 PiB", ByteSize::pb(609), true);
  assert_to_string("609 PB", ByteSize::pb(609), false);
}
<commit_msg>fix arithmetic underflow<commit_after>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      {format!("{} B", self.size)}
    } else {
      let mut exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;
      if exp == 0 {
        exp = 1;
      }

      if si {
        format!("{} {}iB",(self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B",(self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

#[test]
fn test_arithmetic() {
  let x = ByteSize::mb(1);
  let y = ByteSize::kb(100);

  assert_eq!(
    (x + y).as_usize(),
    1100000
  );
  assert_eq!(
    (x + (100*1000)).as_usize(),
    1100000
  );

  assert_eq!(
    (x - y).as_usize(),
    900000
  );
  assert_eq!(
    (x - (100*1000)).as_usize(),
    900000
  );
}

#[allow(dead_code)]
fn assert_display(expected: &str, b: ByteSize) {
  assert_eq!(expected, format!("{}", b));
}

#[test]
fn test_display() {
  assert_display("215 B", ByteSize::b(215));
  assert_display("1 KB", ByteSize::kb(1));
  assert_display("301 KB", ByteSize::kb(301));
  assert_display("419 MB", ByteSize::mb(419));
  assert_display("518 GB", ByteSize::gb(518));
  assert_display("815 TB", ByteSize::tb(815));
  assert_display("609 PB", ByteSize::pb(609));
}

#[allow(dead_code)]
fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
  assert_eq!(expected.to_string(), b.to_string(si));
}

#[test]
fn test_to_string() {
  assert_to_string("215 B", ByteSize::b(215), true);
  assert_to_string("215 B", ByteSize::b(215), false);

  assert_to_string("1 kiB", ByteSize::kib(1), true);
  assert_to_string("1 KB", ByteSize::kib(1), false);

  assert_to_string("293 kiB", ByteSize::kb(301), true);
  assert_to_string("301 KB", ByteSize::kb(301), false);

  assert_to_string("1 MiB", ByteSize::mib(1), true);
  assert_to_string("1048 KB", ByteSize::mib(1), false);

  assert_to_string("399 MiB", ByteSize::mb(419), true);
  assert_to_string("419 MB", ByteSize::mb(419), false);

  assert_to_string("482 GiB", ByteSize::gb(518), true);
  assert_to_string("518 GB", ByteSize::gb(518), false);

  assert_to_string("741 TiB", ByteSize::tb(815), true);
  assert_to_string("815 TB", ByteSize::tb(815), false);

  assert_to_string("540 PiB", ByteSize::pb(609), true);
  assert_to_string("609 PB", ByteSize::pb(609), false);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="nightly", feature(std_misc))]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use libc;
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

/**

This causes program execution to pause for at least the provided duration in
milliseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer or approximately 49 days.

*/
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        let duration = duration.num_milliseconds();
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

/**

This causes program execution to pause for at least the provided number of
milliseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer or approximately 49 days.

*/
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

/**

This causes program execution to pause for at least the provided number of
microseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer microseconds or approximately 71
minutes.

*/
    pub fn delay_microseconds(microseconds: usize) {
        unsafe {
            bindings::delayMicroseconds(microseconds as libc::c_uint);
        }
    }

/**

This returns a number representing the number if milliseconds since your
program called one of the setup functions.

It returns an unsigned 32-bit number which wraps after 49 days.

*/

    pub fn millis() -> usize {
        unsafe {
            bindings::millis() as usize
        }
    }

/**

This returns a number representing the number if microseconds since your
program called one of the setup functions.

It returns an unsigned 32-bit number which wraps after 71 minutes.

*/

    pub fn micros() -> usize {
        unsafe {
            bindings::micros() as usize
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

/**

This attempts to shift your program (or thread in a multi-threaded
program) to a higher priority and enables a real-time scheduling.

The priority parameter should be from 0 (the default) to 99 (the maximum).
This won’t make your program go any faster, but it will give it a bigger slice
of time when other programs are running. The priority parameter works relative
to others – so you can make one program priority 1 and another priority 2 and
it will have the same effect as setting one to 10 and the other to 90 (as long
as no other programs are running with elevated priorities)

The return value is `true` for success and `false` for error. If an error is returned,
the program should then consult the _errno_ global variable, as per the usual
conventions.

_Note_: Only programs running as root can change their priority. If called from
a non-root program then nothing happens.

*/
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    impl_pins!(WiringPi, Gpio, Sys);
    require_root!(WiringPi: 1, Gpio: 18);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }
/**

This sets the pull-up or pull-down resistor mode on the given pin.

Unlike the Arduino, the BCM2835 has both pull-up an down internal resistors.
The parameter pud should be; `Off`, (no pull up/down), `Down` (pull to ground)
or `Up` (pull to 3.3v)

*/
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: usize) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

/**

The PWM generator can run in 2 modes – "balanced" and "mark:space".

The mark:space mode is traditional, however the default mode in the Pi is
"balanced". You can switch modes by supplying the parameter: `Balanced` or
`MarkSpace`.

*/
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: usize) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: usize) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

/**

This initialises the wiringPi system and assumes that the calling program is
going to be using the **wiringPi** pin numbering scheme.

This is a simplified numbering scheme which provides a mapping from virtual
pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers. See
the pins page for a table which maps the **wiringPi** pin number to the Broadcom
GPIO pin number to the physical location on the edge connector.

This function needs to be called with root privileges.

*/
pub fn setup() -> Option<WiringPi<pin::WiringPi>> {
    unsafe {
        if bindings::wiringPiSetup() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This is identical `setup()`, however it allows the calling programs to use the
Broadcom GPIO pin numbers directly with no re-mapping.

This function needs to be called with root privileges.

*/
pub fn setup_gpio() -> Option<WiringPi<pin::Gpio>> {
    unsafe {
        if bindings::wiringPiSetupGpio() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This initialises the wiringPi system but uses the /sys/class/gpio interface
rather than accessing the hardware directly.

This can be called as a non-root user provided the GPIO pins have been
exported before-hand using the gpio program. Pin number in this mode is the
native Broadcom GPIO numbers.

_Note_: In this mode you can only use the pins which have been exported via the
/sys/class/gpio interface. You must export these pins before you call your
program. You can do this in a separate shell-script, or by using the system()
function from inside your program.

Also note that some functions have no effect when using this mode as they’re
not currently possible to action unless called with root privileges.

*/
pub fn setup_sys() -> Option<WiringPi<pin::Sys>> {
    unsafe {
        if bindings::wiringPiSetupSys() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This returns the board revision of the Raspberry Pi.

It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
function when moving from board revision 1 to 2, so if you are using BCM_GPIO
pin numbers, then you need to be aware of the differences.

*/
pub fn board_revision() -> usize {
    unsafe {
        bindings::piBoardRev() as usize
    }
}

///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
///
///It takes the board revision into account.
pub fn to_gpio_number(wpi_number: usize) -> usize {
    unsafe {
        bindings::wpiPinToGpio(wpi_number as libc::c_int) as usize
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: usize) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: usize) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<commit_msg>Move millis and micros to the WiringPi struct<commit_after>#![cfg_attr(feature="nightly", feature(std_misc))]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use libc;
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

/**

This causes program execution to pause for at least the provided duration in
milliseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer or approximately 49 days.

*/
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        let duration = duration.num_milliseconds();
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

/**

This causes program execution to pause for at least the provided number of
milliseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer or approximately 49 days.

*/
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

/**

This causes program execution to pause for at least the provided number of
microseconds.

Due to the multi-tasking nature of Linux it could be longer. Note that the
maximum delay is an unsigned 32-bit integer microseconds or approximately 71
minutes.

*/
    pub fn delay_microseconds(microseconds: usize) {
        unsafe {
            bindings::delayMicroseconds(microseconds as libc::c_uint);
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

/**

This attempts to shift your program (or thread in a multi-threaded
program) to a higher priority and enables a real-time scheduling.

The priority parameter should be from 0 (the default) to 99 (the maximum).
This won’t make your program go any faster, but it will give it a bigger slice
of time when other programs are running. The priority parameter works relative
to others – so you can make one program priority 1 and another priority 2 and
it will have the same effect as setting one to 10 and the other to 90 (as long
as no other programs are running with elevated priorities)

The return value is `true` for success and `false` for error. If an error is returned,
the program should then consult the _errno_ global variable, as per the usual
conventions.

_Note_: Only programs running as root can change their priority. If called from
a non-root program then nothing happens.

*/
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    impl_pins!(WiringPi, Gpio, Sys);
    require_root!(WiringPi: 1, Gpio: 18);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }
/**

This sets the pull-up or pull-down resistor mode on the given pin.

Unlike the Arduino, the BCM2835 has both pull-up an down internal resistors.
The parameter pud should be; `Off`, (no pull up/down), `Down` (pull to ground)
or `Up` (pull to 3.3v)

*/
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: usize) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

/**

The PWM generator can run in 2 modes – "balanced" and "mark:space".

The mark:space mode is traditional, however the default mode in the Pi is
"balanced". You can switch modes by supplying the parameter: `Balanced` or
`MarkSpace`.

*/
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: usize) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: usize) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

/**

This initialises the wiringPi system and assumes that the calling program is
going to be using the **wiringPi** pin numbering scheme.

This is a simplified numbering scheme which provides a mapping from virtual
pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers. See
the pins page for a table which maps the **wiringPi** pin number to the Broadcom
GPIO pin number to the physical location on the edge connector.

This function needs to be called with root privileges.

*/
pub fn setup() -> Option<WiringPi<pin::WiringPi>> {
    unsafe {
        if bindings::wiringPiSetup() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This is identical `setup()`, however it allows the calling programs to use the
Broadcom GPIO pin numbers directly with no re-mapping.

This function needs to be called with root privileges.

*/
pub fn setup_gpio() -> Option<WiringPi<pin::Gpio>> {
    unsafe {
        if bindings::wiringPiSetupGpio() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This initialises the wiringPi system but uses the /sys/class/gpio interface
rather than accessing the hardware directly.

This can be called as a non-root user provided the GPIO pins have been
exported before-hand using the gpio program. Pin number in this mode is the
native Broadcom GPIO numbers.

_Note_: In this mode you can only use the pins which have been exported via the
/sys/class/gpio interface. You must export these pins before you call your
program. You can do this in a separate shell-script, or by using the system()
function from inside your program.

Also note that some functions have no effect when using this mode as they’re
not currently possible to action unless called with root privileges.

*/
pub fn setup_sys() -> Option<WiringPi<pin::Sys>> {
    unsafe {
        if bindings::wiringPiSetupSys() >= 0 {
            Some(WiringPi(PhantomData))
        } else {
            None
        }
    }
}

/**

This returns the board revision of the Raspberry Pi.

It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
function when moving from board revision 1 to 2, so if you are using BCM_GPIO
pin numbers, then you need to be aware of the differences.

*/
pub fn board_revision() -> usize {
    unsafe {
        bindings::piBoardRev() as usize
    }
}

///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
///
///It takes the board revision into account.
pub fn to_gpio_number(wpi_number: usize) -> usize {
    unsafe {
        bindings::wpiPinToGpio(wpi_number as libc::c_int) as usize
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: usize) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: usize) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }
/**

This returns a number representing the number if milliseconds since your
program called one of the setup functions.

It returns an unsigned 32-bit number which wraps after 49 days.

*/

    pub fn millis(&self) -> usize {
        unsafe {
            bindings::millis() as usize
        }
    }

/**

This returns a number representing the number if microseconds since your
program called one of the setup functions.

It returns an unsigned 32-bit number which wraps after 71 minutes.

*/

    pub fn micros(&self) -> usize {
        unsafe {
            bindings::micros() as usize
        }
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<|endoftext|>


<commit_before>
//! slp library for parsing shader languages
//!
//! This is a meta-crate that links all the individual crates together. The
//! crates are re-exported into modules.

extern crate slp_shared;
extern crate slp_lang_htk;
extern crate slp_lang_hst;
extern crate slp_lang_hir;
extern crate slp_lang_cil;
extern crate slp_lang_cst;
extern crate slp_transform_preprocess;
extern crate slp_transform_lexer;
extern crate slp_transform_htk_to_hst;
extern crate slp_transform_hst_to_hir;
extern crate slp_transform_hir_to_cil;
extern crate slp_transform_cil_to_cst;
extern crate slp_transform_cst_printer;
extern crate slp_sequence_hlsl_to_cl;

// pub use slp_shared as shared;

/// The lang crates are intermediate language trees
pub mod lang {
    // pub use slp_lang_htk as htk;
    // pub use slp_lang_hst as hst;
    // pub use slp_lang_hir as hir;
    // pub use slp_lang_cil as cil;
    // pub use slp_lang_cst as cst;
}

/// The transform crates are functions to transform from one language to another
pub mod transform {
    // pub use slp_transform_preprocess as preprocess;
    // pub use slp_transform_lexer as lexer;
    // pub use slp_transform_hst_to_hir as hst_to_hir;
    // pub use slp_transform_hir_to_cil as hir_to_cil;
    // pub use slp_transform_cil_to_cst as cil_to_cst;
    // pub use slp_transform_cst_printer as cst_printer;
}

/// The sequence crates are for combining sequences of transforms
pub mod sequence {
    // pub use slp_sequence_hlsl_to_cl as hlsl_to_cl;
}

#[cfg(test)]
pub mod tests;
<commit_msg>Add pub to crates in meta crate<commit_after>
//! slp library for parsing shader languages
//!
//! This is a meta-crate that links all the individual crates together. The
//! crates are re-exported into modules.

pub extern crate slp_shared;
pub extern crate slp_lang_htk;
pub extern crate slp_lang_hst;
pub extern crate slp_lang_hir;
pub extern crate slp_lang_cil;
pub extern crate slp_lang_cst;
pub extern crate slp_transform_preprocess;
pub extern crate slp_transform_lexer;
pub extern crate slp_transform_htk_to_hst;
pub extern crate slp_transform_hst_to_hir;
pub extern crate slp_transform_hir_to_cil;
pub extern crate slp_transform_cil_to_cst;
pub extern crate slp_transform_cst_printer;
pub extern crate slp_sequence_hlsl_to_cl;

pub use slp_shared as shared;

/// The lang crates are intermediate language trees
pub mod lang {
    pub use slp_lang_htk as htk;
    pub use slp_lang_hst as hst;
    pub use slp_lang_hir as hir;
    pub use slp_lang_cil as cil;
    pub use slp_lang_cst as cst;
}

/// The transform crates are functions to transform from one language to another
pub mod transform {
    pub use slp_transform_preprocess as preprocess;
    pub use slp_transform_lexer as lexer;
    pub use slp_transform_hst_to_hir as hst_to_hir;
    pub use slp_transform_hir_to_cil as hir_to_cil;
    pub use slp_transform_cil_to_cst as cil_to_cst;
    pub use slp_transform_cst_printer as cst_printer;
}

/// The sequence crates are for combining sequences of transforms
pub mod sequence {
    pub use slp_sequence_hlsl_to_cl as hlsl_to_cl;
}

#[cfg(test)]
pub mod tests;
<|endoftext|>


<commit_before>// Copyright (c) 2017 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! This crate is an implementation of basic MySql protocol primitives.
//!
//! This crate:
//! * defines basic MySql constants;
//! * implements necessary functionality for MySql `cached_sha2_password` and
//!   `mysql_native_password` authentication plugins;
//! * implements helper traits for MySql protocol IO;
//! * implements support of named parameters for prepared statements;
//! * implements parsers for a subset of MySql protocol packets;
//! * defines rust representation of MySql protocol value and row;
//! * implements conversion between MySql values and rust types, between MySql rows and tuples
//!   of rust types.
//!
//! ## Supported rust types
//!
//! Crate offers conversion from/to MySql values for following types (please see MySql documentation
//! on supported ranges for numeric types). Following table refers to MySql protocol types
//! (see `Value` struct) and not to MySql column types. Please see [MySql documentation][1] for
//! column and protocol type correspondence:
//!
//! | Type                            | Notes                                                     |
//! | ------------------------------- | -------------------------------------------------------   |
//! | `{i,u}8..{i,u}128`, `{i,u}size` | MySql int/uint will be converted, bytes will be parsed.
⚠ Note that range of `{i,u}128` is greater than supported by MySql integer types but it'll be serialized anyway (as decimal bytes string). |
//! | `f32`                           | MySql float will be converted to `f32`, bytes will be parsed as `f32`.
⚠ MySql double won't be converted to `f32` to avoid precision loss (see #17) |
//! | `f64`                           | MySql float and double will be converted to `f64`, bytes will be parsed as `f64`. |
//! | `bool`                          | MySql int {`0`, `1`} or bytes {`"0x30"`, `"0x31"`}        |
//! | `Vec<u8>`                       | MySql bytes                                               |
//! | `String`                        | MySql bytes parsed as utf8                                |
//! | `Duration` (`std` and `time`)   | MySql time or bytes parsed as MySql time string           |
//! | `time::PrimitiveDateTime`       | MySql date or bytes parsed as MySql date string           |
//! | `time::Date`                    | MySql date or bytes parsed as MySql date string           |
//! | `time::Time`                    | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveTime`             | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveDate`             | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveDateTime`         | MySql date or bytes parsed as MySql date string           |
//! | `uuid::Uuid`                    | MySql bytes parsed using `Uuid::from_slice`               |
//! | `serde_json::Value`             | MySql bytes parsed using `serde_json::from_str`           |
//! | `mysql_common::Deserialized<T : DeserializeOwned>` | MySql bytes parsed using `serde_json::from_str` |
//! | `Option<T: FromValue>`          | Must be used for nullable columns to avoid errors         |
//! | `decimal::Decimal`              | MySql int, uint or bytes parsed using `Decimal::from_str`.
⚠ Note that this type doesn't support full range of MySql `DECIMAL` type. |
//! | `bigdecimal::BigDecimal`        | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_bytes`.
⚠ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
//! | `num_bigint::{BigInt, BigUint}` | MySql int, uint or bytes parsed using `_::parse_bytes`.
⚠ Note that range of this type is greater than supported by MySql integer types but it'll be serialized anyway (as decimal bytes string). |
//!
//! [1]: https://dev.mysql.com/doc/internals/en/binary-protocol-value.html
#![cfg_attr(feature = "nightly", feature(test, const_fn))]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "nightly")]
extern crate test;

pub use bigdecimal;
pub use chrono;
pub use num_bigint;
pub use rust_decimal;
pub use serde;
pub use serde_json;
pub use time;
pub use uuid;

/// This macro is a convenient way to pass named parameters to a statement.
///
/// ```ignore
/// let foo = 42;
/// conn.prep_exec("SELECT :foo, :foo2x", params! {
///     foo,
///     "foo2x" => foo * 2,
/// });
/// ```
#[macro_export]
macro_rules! params {
    () => {};
    (@to_pair $map:expr, $name:expr => $value:expr) => (
        $map.insert(
            std::string::String::from($name),
            $crate::value::Value::from($value),
        )
    );
    (@to_pair $map:expr, $name:ident) => (
        $map.insert(
            std::string::String::from(stringify!($name)),
            $crate::value::Value::from($name),
        )
    );
    (@expand $map:expr;) => {};
    (@expand $map:expr; $name:expr => $value:expr, $($tail:tt)*) => {
        params!(@to_pair $map, $name => $value);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:expr => $value:expr $(, $tail:tt)*) => {
        params!(@to_pair $map, $name => $value);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:ident, $($tail:tt)*) => {
        params!(@to_pair $map, $name);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:ident $(, $tail:tt)*) => {
        params!(@to_pair $map, $name);
        params!(@expand $map; $($tail)*);
    };
    ($i:ident, $($tail:tt)*) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i, $($tail)*);
            $crate::params::Params::Named(map)
        }
    };
    ($i:expr => $($tail:tt)*) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i => $($tail)*);
            $crate::params::Params::Named(map)
        }
    };
    ($i:ident) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i);
            $crate::params::Params::Named(map)
        }
    }
}

/// Non panicking Slice::split_at
macro_rules! split_at_or_err {
    ($reader:expr, $at:expr, $msg:expr) => {
        if $reader.len() >= $at {
            Ok($reader.split_at($at))
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof, $msg))
        }
    };
}

/// Reads MySql's length-encoded string
#[macro_export]
macro_rules! read_lenenc_str {
    ($reader:expr) => {{
        let reader = $reader;
        reader.read_lenenc_int().and_then(|len| {
            let (value, rest) = split_at_or_err!(
                reader,
                len as usize,
                "EOF while reading length-encoded string"
            )?;
            *reader = rest;
            Ok(value)
        })
    }};
}

pub mod constants;
pub mod crypto;
pub mod io;
pub mod misc;
pub mod named_params;
#[macro_use]
pub mod packets;
pub mod params;
pub mod proto;
pub mod row;
pub mod scramble;
pub mod value;

#[cfg(test)]
#[test]
fn params_macro_test() {
    use crate::{params::Params, value::Value};

    let foo = 42;
    let bar = "bar";

    assert_eq!(
        Params::from(vec![(String::from("foo"), Value::Int(42))]),
        params! { foo }
    );
    assert_eq!(
        Params::from(vec![(String::from("foo"), Value::Int(42))]),
        params! { foo, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, "bar" => bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, "bar" => bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, "bar" => bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, "bar" => bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, bar, }
    );
}
<commit_msg>Restore the panicking behaviour of the params macro<commit_after>// Copyright (c) 2017 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! This crate is an implementation of basic MySql protocol primitives.
//!
//! This crate:
//! * defines basic MySql constants;
//! * implements necessary functionality for MySql `cached_sha2_password` and
//!   `mysql_native_password` authentication plugins;
//! * implements helper traits for MySql protocol IO;
//! * implements support of named parameters for prepared statements;
//! * implements parsers for a subset of MySql protocol packets;
//! * defines rust representation of MySql protocol value and row;
//! * implements conversion between MySql values and rust types, between MySql rows and tuples
//!   of rust types.
//!
//! ## Supported rust types
//!
//! Crate offers conversion from/to MySql values for following types (please see MySql documentation
//! on supported ranges for numeric types). Following table refers to MySql protocol types
//! (see `Value` struct) and not to MySql column types. Please see [MySql documentation][1] for
//! column and protocol type correspondence:
//!
//! | Type                            | Notes                                                     |
//! | ------------------------------- | -------------------------------------------------------   |
//! | `{i,u}8..{i,u}128`, `{i,u}size` | MySql int/uint will be converted, bytes will be parsed.
⚠ Note that range of `{i,u}128` is greater than supported by MySql integer types but it'll be serialized anyway (as decimal bytes string). |
//! | `f32`                           | MySql float will be converted to `f32`, bytes will be parsed as `f32`.
⚠ MySql double won't be converted to `f32` to avoid precision loss (see #17) |
//! | `f64`                           | MySql float and double will be converted to `f64`, bytes will be parsed as `f64`. |
//! | `bool`                          | MySql int {`0`, `1`} or bytes {`"0x30"`, `"0x31"`}        |
//! | `Vec<u8>`                       | MySql bytes                                               |
//! | `String`                        | MySql bytes parsed as utf8                                |
//! | `Duration` (`std` and `time`)   | MySql time or bytes parsed as MySql time string           |
//! | `time::PrimitiveDateTime`       | MySql date or bytes parsed as MySql date string           |
//! | `time::Date`                    | MySql date or bytes parsed as MySql date string           |
//! | `time::Time`                    | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveTime`             | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveDate`             | MySql date or bytes parsed as MySql date string           |
//! | `chrono::NaiveDateTime`         | MySql date or bytes parsed as MySql date string           |
//! | `uuid::Uuid`                    | MySql bytes parsed using `Uuid::from_slice`               |
//! | `serde_json::Value`             | MySql bytes parsed using `serde_json::from_str`           |
//! | `mysql_common::Deserialized<T : DeserializeOwned>` | MySql bytes parsed using `serde_json::from_str` |
//! | `Option<T: FromValue>`          | Must be used for nullable columns to avoid errors         |
//! | `decimal::Decimal`              | MySql int, uint or bytes parsed using `Decimal::from_str`.
⚠ Note that this type doesn't support full range of MySql `DECIMAL` type. |
//! | `bigdecimal::BigDecimal`        | MySql int, uint, floats or bytes parsed using `BigDecimal::parse_bytes`.
⚠ Note that range of this type is greater than supported by MySql `DECIMAL` type but it'll be serialized anyway. |
//! | `num_bigint::{BigInt, BigUint}` | MySql int, uint or bytes parsed using `_::parse_bytes`.
⚠ Note that range of this type is greater than supported by MySql integer types but it'll be serialized anyway (as decimal bytes string). |
//!
//! [1]: https://dev.mysql.com/doc/internals/en/binary-protocol-value.html
#![cfg_attr(feature = "nightly", feature(test, const_fn))]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "nightly")]
extern crate test;

pub use bigdecimal;
pub use chrono;
pub use num_bigint;
pub use rust_decimal;
pub use serde;
pub use serde_json;
pub use time;
pub use uuid;

/// This macro is a convenient way to pass named parameters to a statement.
///
/// ```ignore
/// let foo = 42;
/// conn.prep_exec("SELECT :foo, :foo2x", params! {
///     foo,
///     "foo2x" => foo * 2,
/// });
/// ```
#[macro_export]
macro_rules! params {
    () => {};
    (@to_pair $map:expr, $name:expr => $value:expr) => (
        let entry = $map.entry(std::string::String::from($name));
        if let std::collections::hash_map::Entry::Occupied(_) = entry {
            panic!("Redefinition of named parameter `{}'", entry.key());
        } else {
            entry.or_insert($crate::value::Value::from($value));
        }
    );
    (@to_pair $map:expr, $name:ident) => (
        let entry = $map.entry(std::string::String::from(stringify!($name)));
        if let std::collections::hash_map::Entry::Occupied(_) = entry {
            panic!("Redefinition of named parameter `{}'", entry.key());
        } else {
            entry.or_insert($crate::value::Value::from($name));
        }
    );
    (@expand $map:expr;) => {};
    (@expand $map:expr; $name:expr => $value:expr, $($tail:tt)*) => {
        params!(@to_pair $map, $name => $value);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:expr => $value:expr $(, $tail:tt)*) => {
        params!(@to_pair $map, $name => $value);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:ident, $($tail:tt)*) => {
        params!(@to_pair $map, $name);
        params!(@expand $map; $($tail)*);
    };
    (@expand $map:expr; $name:ident $(, $tail:tt)*) => {
        params!(@to_pair $map, $name);
        params!(@expand $map; $($tail)*);
    };
    ($i:ident, $($tail:tt)*) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i, $($tail)*);
            $crate::params::Params::Named(map)
        }
    };
    ($i:expr => $($tail:tt)*) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i => $($tail)*);
            $crate::params::Params::Named(map)
        }
    };
    ($i:ident) => {
        {
            let mut map: std::collections::HashMap<std::string::String, $crate::value::Value, _> = std::default::Default::default();
            params!(@expand (&mut map); $i);
            $crate::params::Params::Named(map)
        }
    }
}

/// Non panicking Slice::split_at
macro_rules! split_at_or_err {
    ($reader:expr, $at:expr, $msg:expr) => {
        if $reader.len() >= $at {
            Ok($reader.split_at($at))
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof, $msg))
        }
    };
}

/// Reads MySql's length-encoded string
#[macro_export]
macro_rules! read_lenenc_str {
    ($reader:expr) => {{
        let reader = $reader;
        reader.read_lenenc_int().and_then(|len| {
            let (value, rest) = split_at_or_err!(
                reader,
                len as usize,
                "EOF while reading length-encoded string"
            )?;
            *reader = rest;
            Ok(value)
        })
    }};
}

pub mod constants;
pub mod crypto;
pub mod io;
pub mod misc;
pub mod named_params;
#[macro_use]
pub mod packets;
pub mod params;
pub mod proto;
pub mod row;
pub mod scramble;
pub mod value;

#[cfg(test)]
#[test]
fn params_macro_test() {
    use crate::{params::Params, value::Value};

    let foo = 42;
    let bar = "bar";

    assert_eq!(
        Params::from(vec![(String::from("foo"), Value::Int(42))]),
        params! { foo }
    );
    assert_eq!(
        Params::from(vec![(String::from("foo"), Value::Int(42))]),
        params! { foo, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, "bar" => bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, "bar" => bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, "bar" => bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, bar }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { foo, "bar" => bar, }
    );
    assert_eq!(
        Params::from(vec![
            (String::from("foo"), Value::Int(42)),
            (String::from("bar"), Value::Bytes((&b"bar"[..]).into())),
        ]),
        params! { "foo" => foo, bar, }
    );
}

#[test]
#[should_panic(expected = "Redefinition of named parameter `a'")]
fn params_macro_should_panic_on_named_param_redefinition() {
    params! {"a" => 1, "b" => 2, "a" => 3};
}
<|endoftext|>