<commit_before>#![feature(core)]

/// Generate a new iterable witn a list comprehension
/// ```
/// let x: Vec<i32> = gen!(x*4 => x in [1, 2, 3, 4]);
/// ```
#[macro_export]
macro_rules! gen {
    [$e:expr => $variable:ident in $iterable:expr] => (
        $iterable.iter().cloned().map(|$variable| $e).collect()
    );
    [$e:expr => $variable:ident in $iterable:expr, $condition:expr] => (
        $iterable.iter().cloned().filter(|$variable| $condition).map(|$variable| $e).collect()
    );
}

#[cfg(test)]
mod test;
<commit_msg>add more comments<commit_after>#![feature(core)]

/// Generate a new iterable witn a list comprehension. This macro tries to follow the syntax of
/// Python's list comprehensions. This is a very flexable macro that allows the generation of any
/// iterable that implements `std::iter::FromIterator`. The resulting type will be determined by
/// the type of the variable that you are attempting to assign to. You can create a `Vec`:
///
/// ```
/// let x: Vec<i32> = gen![i*30 => i in [1, 2, 3, 4, 5]];
/// ```
///
/// You can generate a `HashSet`:
///
/// ```
/// let x: HashSet<i32> = gen![i*30 => i in [1, 2, 3, 4, 5]];
/// ```
///
/// You can even use conditionals to generate stuff:
///
/// ```
/// let x: HashSet<i32> = gen![i => i in [1, 2, 3, 4, 5], x % 2 == 0];
/// // outputs vec![2, 4]
/// ```
///
/// Comparisson to Python's list comprehension
/// ===
///
/// Python
/// ---
/// ```python
/// x = [i*4 for i in range(1, 5)]
/// ```
///
/// Rust with gen! macro
/// ---
/// ```
/// let x: Vec<i32> = gen!(x*4 => x in [1, 2, 3, 4]);
/// ```
#[macro_export]
macro_rules! gen {
    [$e:expr => $variable:ident in $iterable:expr] => (
        $iterable.iter().cloned().map(|$variable| $e).collect()
    );
    [$e:expr => $variable:ident in $iterable:expr, $condition:expr] => (
        $iterable.iter().cloned().filter(|$variable| $condition).map(|$variable| $e).collect()
    );
}

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


<commit_before>#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate ole32;

#[cfg(not(target_os = "windows"))]
use std::env;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut data_dir = env::home_dir().unwrap();
    data_dir.push("Library/Application Support");
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut data_dir = PathBuf::new();
    match env::var_os("XDG_DATA_HOME") {
        Some(dir) => { data_dir.push(dir); },
        None => {
            data_dir.push(env::home_dir().unwrap());
            data_dir.push(".local/share");
        },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push("/Library/Application Support");
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/usr/local/share";
    match env::var_os("XDG_DATA_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_config_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut config_dir = PathBuf::new();
    match env::var_os("XDG_CONFIG_HOME") {
        Some(dir) => { config_dir.push(dir); },
        None => {
            config_dir.push(env::home_dir().unwrap());
            config_dir.push(".config");
        },
    };
    if app.is_some() {
        config_dir.push(app.unwrap());
    }
    config_dir
}

#[cfg(target_os = "macos")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_config_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/etc/xdg";
    match env::var_os("XDG_CONFIG_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut cache_dir = env::home_dir().unwrap();
    cache_dir.push("Library/Caches");
    if app.is_some() {
        cache_dir.push(app.unwrap());
    }
    cache_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut cache_dir = PathBuf::new();
    match env::var_os("XDG_CACHE_HOME") {
        Some(dir) => { cache_dir.push(dir); },
        None => {
            cache_dir.push(env::home_dir().unwrap());
            cache_dir.push(".cache");
        },
    };
    if app.is_some() {
        cache_dir.push(app.unwrap());
    }
    cache_dir
}

#[cfg(target_os = "macos")]
pub fn user_log_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut log_dir = env::home_dir().unwrap();
    log_dir.push("Library/Logs");
    if app.is_some() {
        log_dir.push(app.unwrap());
    }
    log_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_cache_dir(app, author);
    log_dir.push("log");
    log_dir
}

#[cfg(target_os = "windows")]
static APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1052149211,
    Data2: 26105,
    Data3: 19702,
    Data4: [160, 58, 227, 239, 101, 114, 159, 61],
};

#[cfg(target_os = "windows")]
static COMMON_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1655397762,
    Data2: 64961,
    Data3: 19907,
    Data4: [169, 221, 7, 13, 29, 73, 93, 151],
};

#[cfg(target_os = "windows")]
static LOCAL_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 4055050117,
    Data2: 28602,
    Data3: 20431,
    Data4: [157, 85, 123, 142, 127, 21, 112, 145],
};

#[cfg(target_os = "windows")]
use std::ptr;

#[cfg(target_os = "windows")]
use std::ffi::OsString;

#[cfg(target_os = "windows")]
use std::os::windows::ffi::OsStringExt;

#[cfg(target_os = "windows")]
use std::slice;

#[cfg(target_os = "windows")]
fn get_dir(id: &winapi::shtypes::KNOWNFOLDERID) -> Result<OsString, ()> {
    let mut result: winapi::PWSTR = ptr::null_mut();
    let error;
    unsafe {
        error = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(),
                                              &mut result);
    }
    if error != winapi::S_OK {
        //let _ = io::stderr().write(format!("error: {}\n", error));
        return Err(());
    }
    unsafe {
        let mut len = 0;
        let mut cur = result;
        while *cur != 0 {
            len += 1;
            cur = cur.offset(1);
        }
        let os_string: OsString =
            OsStringExt::from_wide(slice::from_raw_parts(result, len));
        ole32::CoTaskMemFree(result as *mut _);
        Ok(os_string)
    }
}

#[cfg(target_os = "windows")]
pub fn user_data_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    let dir_id = if roaming { APPDATA_GUID } else { LOCAL_APPDATA_GUID };
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&dir_id).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn site_data_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&COMMON_APPDATA_GUID).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "windows")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "windows")]
pub fn user_cache_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut cache_dir = user_data_dir(app, author, false);
    cache_dir.push("Cache");
    cache_dir
}

#[cfg(target_os = "windows")]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_data_dir(app, author, false);
    log_dir.push("Logs");
    log_dir
}

#[cfg(test)]
mod tests {

    use std::io::{self, Write};
    use std::path::PathBuf;

    fn to_stderr(name: &str, value: PathBuf) {
        let _ = io::stderr().write(format!("{}: {}\n", name,
                                           value.to_str().unwrap()).as_bytes());
    }

    #[test]
    fn output_dirs() {
        to_stderr("user data dir",
                  super::user_data_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site data dir",
                  super::site_data_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user config dir",
                  super::user_config_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site config dir",
                  super::site_config_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user cache dir",
                  super::user_cache_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user log dir",
                  super::user_log_dir(Some("AppDirs"), Some("djc")));
    }

}
<commit_msg>Add helper function for macOS variants<commit_after>#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate ole32;

#[cfg(not(target_os = "windows"))]
use std::env;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
fn home_dir_relative(rel: &str, app: Option<&str>) -> PathBuf {
    let mut data_dir = env::home_dir().unwrap();
    data_dir.push(rel);
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    home_dir_relative("Library/Application Support", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut data_dir = PathBuf::new();
    match env::var_os("XDG_DATA_HOME") {
        Some(dir) => { data_dir.push(dir); },
        None => {
            data_dir.push(env::home_dir().unwrap());
            data_dir.push(".local/share");
        },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push("/Library/Application Support");
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/usr/local/share";
    match env::var_os("XDG_DATA_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_config_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut config_dir = PathBuf::new();
    match env::var_os("XDG_CONFIG_HOME") {
        Some(dir) => { config_dir.push(dir); },
        None => {
            config_dir.push(env::home_dir().unwrap());
            config_dir.push(".config");
        },
    };
    if app.is_some() {
        config_dir.push(app.unwrap());
    }
    config_dir
}

#[cfg(target_os = "macos")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_config_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/etc/xdg";
    match env::var_os("XDG_CONFIG_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Caches", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut cache_dir = PathBuf::new();
    match env::var_os("XDG_CACHE_HOME") {
        Some(dir) => { cache_dir.push(dir); },
        None => {
            cache_dir.push(env::home_dir().unwrap());
            cache_dir.push(".cache");
        },
    };
    if app.is_some() {
        cache_dir.push(app.unwrap());
    }
    cache_dir
}

#[cfg(target_os = "macos")]
pub fn user_log_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Logs", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_cache_dir(app, author);
    log_dir.push("log");
    log_dir
}

#[cfg(target_os = "windows")]
static APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1052149211,
    Data2: 26105,
    Data3: 19702,
    Data4: [160, 58, 227, 239, 101, 114, 159, 61],
};

#[cfg(target_os = "windows")]
static COMMON_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1655397762,
    Data2: 64961,
    Data3: 19907,
    Data4: [169, 221, 7, 13, 29, 73, 93, 151],
};

#[cfg(target_os = "windows")]
static LOCAL_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 4055050117,
    Data2: 28602,
    Data3: 20431,
    Data4: [157, 85, 123, 142, 127, 21, 112, 145],
};

#[cfg(target_os = "windows")]
use std::ptr;

#[cfg(target_os = "windows")]
use std::ffi::OsString;

#[cfg(target_os = "windows")]
use std::os::windows::ffi::OsStringExt;

#[cfg(target_os = "windows")]
use std::slice;

#[cfg(target_os = "windows")]
fn get_dir(id: &winapi::shtypes::KNOWNFOLDERID) -> Result<OsString, ()> {
    let mut result: winapi::PWSTR = ptr::null_mut();
    let error;
    unsafe {
        error = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(),
                                              &mut result);
    }
    if error != winapi::S_OK {
        //let _ = io::stderr().write(format!("error: {}\n", error));
        return Err(());
    }
    unsafe {
        let mut len = 0;
        let mut cur = result;
        while *cur != 0 {
            len += 1;
            cur = cur.offset(1);
        }
        let os_string: OsString =
            OsStringExt::from_wide(slice::from_raw_parts(result, len));
        ole32::CoTaskMemFree(result as *mut _);
        Ok(os_string)
    }
}

#[cfg(target_os = "windows")]
pub fn user_data_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    let dir_id = if roaming { APPDATA_GUID } else { LOCAL_APPDATA_GUID };
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&dir_id).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn site_data_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&COMMON_APPDATA_GUID).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "windows")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "windows")]
pub fn user_cache_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut cache_dir = user_data_dir(app, author, false);
    cache_dir.push("Cache");
    cache_dir
}

#[cfg(target_os = "windows")]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_data_dir(app, author, false);
    log_dir.push("Logs");
    log_dir
}

#[cfg(test)]
mod tests {

    use std::io::{self, Write};
    use std::path::PathBuf;

    fn to_stderr(name: &str, value: PathBuf) {
        let _ = io::stderr().write(format!("{}: {}\n", name,
                                           value.to_str().unwrap()).as_bytes());
    }

    #[test]
    fn output_dirs() {
        to_stderr("user data dir",
                  super::user_data_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site data dir",
                  super::site_data_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user config dir",
                  super::user_config_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site config dir",
                  super::site_config_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user cache dir",
                  super::user_cache_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user log dir",
                  super::user_log_dir(Some("AppDirs"), Some("djc")));
    }

}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! match_any {
    ($a:ident => $($x:ident: $t:ty => $b:block),+) => {
        {
            $(
                if let Some($x) = $a.downcast_ref::<$t>() {
                    $b
                };
            )+
        }
    }
}
<commit_msg>Expression instead of identifier<commit_after>#[macro_export]
macro_rules! match_any {
    ($a:expr => $($x:ident: $t:ty => $b:block),+) => {
        {
            $(
                if let Some($x) = $a.downcast_ref::<$t>() {
                    $b
                };
            )+
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(dead_code)]
#![allow(unused_variables)]
#![feature(conservative_impl_trait)]
#![feature(associated_consts)]
#![feature(slice_patterns)]

extern crate nodrop;
extern crate num_traits;

mod util;
pub mod rudymap;
mod key;

pub use key::Key;
mod rudyset;

//pub use rudyset::RudySet;
//pub use rudymap::RudyMap;

<commit_msg>Make RudySet public, include RudyMap/Set in lib.rs<commit_after>#![allow(unused_imports)]
#![allow(dead_code)]
#![allow(unused_variables)]
#![feature(conservative_impl_trait)]
#![feature(associated_consts)]
#![feature(slice_patterns)]

extern crate nodrop;
extern crate num_traits;

mod util;
mod key;

pub mod rudymap;
pub mod rudyset;

pub use key::Key;
pub use rudyset::RudySet;
pub use rudymap::RudyMap;
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![feature(collections)]
#![cfg_attr(test, feature(step_by))]

#[macro_use]
extern crate bitflags;
extern crate libc;

pub use ffi::*;

use libc::consts::os::extra::*;
use libc::funcs::extra::kernel32;
use libc::{ c_void, c_int, HANDLE, DWORD };
use std::{ ptr, mem, io };
use std::io::{ Error, ErrorKind };

mod ffi;

pub struct CommEventWaiter<'a> {
	comm_handle: &'a mut c_void
}
impl<'a> CommEventWaiter<'a> {
	pub fn wait_for_event(&mut self) -> Result<CommEventFlags, DWORD> {
		let mut events = CommEventFlags::empty();
		let (succeded, err) = unsafe { (
			WaitCommEvent(self.comm_handle, &mut events, ptr::null_mut()) != 0,
			kernel32::GetLastError()
		) };

		if succeded {
			Ok(events)
		} else {
			Err(err)
		}
	}
}
unsafe impl<'a> Send for CommEventWaiter<'a> { }

/// A serial connection
pub struct Connection {
	// Pointer to the serial connection
	comm_handle: HANDLE
}
impl Connection {
	/// Open a new connection via port `port` with baud rate `baud_rate`
	pub fn new(port: &str, baud_rate: u32) -> io::Result<Connection> {
		let (comm_handle, cf_result) = unsafe {
			let mut port_u16: Vec<_> = port.utf16_units().collect();
			port_u16.push(0);
			(
				kernel32::CreateFileW(port_u16.as_ptr(),
					GENERIC_READ | GENERIC_WRITE,
					0,
					ptr::null_mut(),
					OPEN_EXISTING,
					libc::FILE_ATTRIBUTE_NORMAL,
					ptr::null_mut()),
				kernel32::GetLastError() as c_int
			)
		};

		if comm_handle == INVALID_HANDLE_VALUE {
			Err(match cf_result {
				ERROR_ACCESS_DENIED =>
					Error::new(ErrorKind::AlreadyExists, "Access denied, port might be busy"),
				ERROR_FILE_NOT_FOUND =>
					Error::new(ErrorKind::NotFound, "COM port does not exist"),
				_ => Error::new(ErrorKind::Other, "Invalid COM port handle")
			})
		} else {
			let mut conn = Connection{ comm_handle: comm_handle };
			let mut dcb = match conn.get_comm_state() {
				Ok(dcb) => dcb,
				Err(_) => return Err(Error::new(ErrorKind::Other, "Error getting comm state"))
			};

			dcb.BaudRate = baud_rate;
			dcb.ByteSize = 8;
			dcb.StopBits = ONESTOPBIT;
			dcb.Parity = NOPARITY;
			dcb.set_dtr_control(DTR_CONTROL::ENABLE);
			if let Err(_) = conn.set_comm_state(dcb) {
				return Err(Error::new(ErrorKind::Other, "Error setting comm state"))
			} else {
				conn.set_timeout(40).unwrap();
				unsafe { PurgeComm(conn.comm_handle, PURGE_RXCLEAR | PURGE_TXCLEAR); }
				Ok(conn)
			}
		}
	}

	/// Retrieve the current control settings for this communications device
	fn get_comm_state(&mut self) -> Result<DCB, ()> {
		unsafe {
			let mut dcb = mem::zeroed();
			if GetCommState(self.comm_handle, &mut dcb) == 0 {
				Err(())
			} else {
				Ok(dcb)
			}
		}
	}

	/// Configures this communications device according to specifications in a device-control block,
	/// `dcb`.
	fn set_comm_state(&mut self, mut dcb: DCB) -> Result<(), ()> {
		if unsafe { SetCommState(self.comm_handle, &mut dcb) } == 0 {
			Err(())
		} else {
			Ok(())
		}
	}

	pub fn comm_event_waiter<'a>(&self) -> CommEventWaiter<'a> {
		CommEventWaiter{ comm_handle: unsafe { mem::transmute(self.comm_handle) } }
	}

	/// Set interval and total timeouts to `timeout_ms`
	pub fn set_timeout(&mut self, timeout_ms: u32) -> Result<(), ()> {
		unsafe {
			if SetCommTimeouts(self.comm_handle, &mut COMMTIMEOUTS{
				ReadIntervalTimeout: timeout_ms,
				ReadTotalTimeoutMultiplier: timeout_ms,
				ReadTotalTimeoutConstant: timeout_ms,
				WriteTotalTimeoutMultiplier: timeout_ms,
				WriteTotalTimeoutConstant: timeout_ms,
			}) != 0
			{
				Ok(())
			} else {
				Err(())
			}
		}
	}

	/// Read into `buf` until `delim` is encountered. Return n.o. bytes read on success,
	/// and an IO error on failure.
	pub fn read_until(&mut self, delim: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
		use std::io::Read;

		let mut byte = [0_u8];
		loop {
			match self.read(&mut byte) {
				Err(e) => return Err(e),
				Ok(0) => { println!("read 0 bytes"); break },
				Ok(_) => (),
			};

			let buf_len = buf.len();
			if byte[0] == delim {
				return Ok(buf_len);
			}

			if buf_len == buf.capacity() {
				buf.reserve(buf_len);
			}
			buf.push(byte[0])
		}

		// Delimiter was not found before end of stream or timeout
		Err(Error::new(ErrorKind::Other, "Delimiter was not found"))
	}

	/// Read until newline. Return n.o. bytes read on success
	pub fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
		self.read_until('\n' as u8, buf)
	}
}
impl io::Read for Connection {
	fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
		if buf.len() == 0 {
			return Ok(0)
		}

		let mut n_bytes_read = 0;
		let (succeded, err) = unsafe { (
			kernel32::ReadFile(self.comm_handle,
				buf.as_mut_ptr() as *mut c_void,
				buf.len() as u32,
				&mut n_bytes_read,
				ptr::null_mut()) > 0,
			kernel32::GetLastError() as c_int
		) };

		if succeded {
			if n_bytes_read == 0 {
				Err(Error::new(ErrorKind::TimedOut, "Operation timed out"))
			} else {
				Ok(n_bytes_read as usize)
			}
		} else {
			Err(match err {
				ERROR_INVALID_USER_BUFFER =>
					Error::new(ErrorKind::InvalidInput, "Supplied buffer is invalid"),
				ERROR_NOT_ENOUGH_MEMORY =>
					Error::new(ErrorKind::Other, "Too many I/O requests"),
				ERROR_OPERATION_ABORTED =>
					Error::new(ErrorKind::Interrupted, "Operation was canceled"),
				_ => Error::new(ErrorKind::Other, format!("Read failed with 0x{:x}", err))
			})
		}
	}
}
impl io::Write for Connection {
	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
		let mut n_bytes_written = 0;

		let (succeded, err) = unsafe { (
			kernel32::WriteFile(self.comm_handle,
				mem::transmute(buf.as_ptr()),
				buf.len() as u32,
				&mut n_bytes_written,
				ptr::null_mut()) != 0,
			kernel32::GetLastError() as c_int
		) };

		if succeded {
			Ok(n_bytes_written as usize)
		} else {
			Err(match err {
				ERROR_INVALID_USER_BUFFER =>
					Error::new(ErrorKind::InvalidInput, "Supplied buffer is invalid"),
				ERROR_NOT_ENOUGH_MEMORY =>
					Error::new(ErrorKind::Other, "Too many I/O requests"),
				ERROR_OPERATION_ABORTED =>
					Error::new(ErrorKind::Interrupted, "Operation was canceled"),
				_ => Error::new(ErrorKind::Other, format!("Write failed with 0x{:x}", err))
			})
		}
	}

	fn flush(&mut self) -> io::Result<()> {
		let (succeded, err) = unsafe { (
			kernel32::FlushFileBuffers(self.comm_handle) != 0,
			kernel32::GetLastError() as c_int
		)};

		if succeded {
			Ok(())
		} else {
			Err(match err {
				ERROR_INVALID_HANDLE =>
					Error::new(ErrorKind::InvalidInput, "Communications handle is invalid"),
				_ => Error::new(ErrorKind::Other, format!("Flush failed with 0x{:x}", err))
			})
		}
	}
}
impl Drop for Connection {
	fn drop(&mut self) {
		let e = unsafe { kernel32::CloseHandle(self.comm_handle) };
		if e < 1 {
			panic!("CloseHandle failed with 0x{:x}", e)
		}
	}
}
unsafe impl Send for Connection { }

// Some tests requires correct code to be running on connected serial device

// // Should work with any simple echo code on the arduino
// #[test]
// fn echo_test() {
// 	use std::io::Write;
// 	use std::thread;

// 	let port = "COM8";
// 	let baud_rate = 9600_u32;
// 	let mut connection = Connection::new(port, baud_rate).unwrap();
// 	thread::sleep_ms(2000);

// 	for i in 0..20 {
// 		let test_str = format!("One two {}\n", i);

// 		let n_bytes_written = connection.write(test_str.as_bytes());

// 		let mut buffer = Vec::with_capacity(20);

// 		let n_bytes_read = connection.read_line(&mut buffer);
// 		let read_string = String::from_utf8(buffer).unwrap();

// 		println!("Bytes written: {:?}, Bytes read: {:?}, String read: {}",
// 			n_bytes_written, n_bytes_read, read_string);
// 	}
// }

// Colorswirl. Works with arduino running LEDstream
#[test]
fn colorswirl_test() {
	use std::thread;
	use std::io::Write;

	let port = "COM8";
	let baud_rate = 115_200;
	let mut connection = Connection::new(port, baud_rate).unwrap();

	thread::sleep_ms(2000);

	let n_leds = 32;
	let pixel_size = 3;
	let header_size = 6;
	let mut buffer: Vec<u8> = (0..(header_size + n_leds * pixel_size)).map(|_| 0).collect();

	// A special header / magic word is expected by the corresponding LED streaming code
	// running on the Arduino. This only needs to be initialized once because the number of
	// LEDs remains constant:
	buffer[0] = 'A' as u8;                    // Magic word
	buffer[1] = 'd' as u8;
	buffer[2] = 'a' as u8;
	buffer[3] = ((n_leds - 1) >> 8) as u8;    // LED count high byte
	buffer[4] = ((n_leds - 1) & 0xff) as u8;  // LED count low byte
	buffer[5] = buffer[3] ^ buffer[4] ^ 0x55; // Checksum

	let mut main_sin = 0.0_f32;
	let mut main_hue = 0_u16;

	for _ in 0..1_000 {
		let mut internal_sin = main_sin;
		let mut internal_hue = main_hue;

		let (mut r, mut g, mut b): (u8, u8, u8);
		// Start at position 6, after the LED header/magic word
		for i in (6..buffer.len()).step_by(3) {
			// Fixed-point hue-to-RGB conversion.  'internal_hue' is an integer in the
			// range of 0 to 1535, where 0 = red, 256 = yellow, 512 = green, etc.
			// The high byte (0-5) corresponds to the sextant within the color
			// wheel, while the low byte (0-255) is the fractional part between
			// the primary/secondary colors.
			let pri_sec_frac = (internal_hue & 255) as u8;
			match (internal_hue >> 8) % 6 {
				0 => {
					r = 255;
					g = pri_sec_frac;
					b = 0;
				}, 1 => {
					r = 255 - pri_sec_frac;
					g = 255;
					b = 0;
				}, 2 => {
					r = 0;
					g = 255;
					b = pri_sec_frac;
				}, 3 => {
					r = 0;
					g = 255 - pri_sec_frac;
					b = 255;
				}, 4 => {
					r = pri_sec_frac;
					g = 0;
					b = 255;
				}, _ => {
					r = 255;
					g = 0;
					b = 255 - pri_sec_frac;
				}
			}

			// Resulting hue is multiplied by brightness in the range of 0 to 255
			// (0 = off, 255 = brightest).  Gamma corrrection (the 'powf' function
			// here) adjusts the brightness to be more perceptually linear.
			let brightness = (0.5 + internal_sin.sin() * 0.5).powf(2.8);
			buffer[i]     = (r as f32 * brightness) as u8;
			buffer[i + 1] = (g as f32 * brightness) as u8;
			buffer[i + 2] = (b as f32 * brightness) as u8;

			// Each pixel is slightly offset in both hue and brightness
			internal_hue += 40;
			internal_sin += 0.3;
		}

		// Slowly rotate hue and brightness in opposite directions
		main_hue = (main_hue + 4) % 1536;
		main_sin -= 0.03;

		// Issue color data to LEDs
		connection.write(&buffer[..]).unwrap();
		connection.flush().unwrap(); // Not necessary, just testing

		// The arduino can't handle it if we go too fast
		thread::sleep_ms(2);
	}
}<commit_msg>forgot to commit lib.rs in previous<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![feature(collections)]
#![cfg_attr(test, feature(step_by))]

#[macro_use]
extern crate bitflags;
extern crate libc;
pub use ffi::*;

use libc::consts::os::extra::*;
use libc::funcs::extra::kernel32;
use libc::{ c_void, c_int, HANDLE };
use std::{ ptr, mem, io };
use std::io::{ Error, ErrorKind };

mod ffi;

fn system_to_io_err(operation: &'static str, error_code: c_int) -> io::Error {
	use std::io::ErrorKind::*;

	let (error_kind, message) = match error_code {
		ERROR_ACCESS_DENIED => (AlreadyExists, "Access denied. Resource might be busy"),
		ERROR_FILE_NOT_FOUND => (NotFound, "Serial port not found"),
		ERROR_INVALID_USER_BUFFER => (InvalidInput, "Supplied buffer is invalid"),
		ERROR_NOT_ENOUGH_MEMORY => (Other, "Too many I/O requests, not enough memory"),
		ERROR_OPERATION_ABORTED => (Interrupted, "Operation was canceled"),
		ERROR_INVALID_HANDLE => (InvalidInput, "Communications handle is invalid"),
		_ => (Other, "unmatched error"),
	};

	Error::new(error_kind,
		format!(r#"Operation `{}` failed with code 0x{:x} and message "{}""#,
			operation, error_code, message))
}

/// A serial connection
pub struct Connection {
	// Pointer to the serial connection
	comm_handle: HANDLE
}
impl Connection {
	/// Open a new connection via port `port` with baud rate `baud_rate`
	pub fn new(port: &str, baud_rate: u32) -> io::Result<Connection> {
		let (comm_handle, err) = unsafe {
			let mut port_u16: Vec<_> = port.utf16_units().collect();
			port_u16.push(0);
			(
				kernel32::CreateFileW(port_u16.as_ptr(),
					GENERIC_READ | GENERIC_WRITE,
					0,
					ptr::null_mut(),
					OPEN_EXISTING,
					libc::FILE_ATTRIBUTE_NORMAL,
					ptr::null_mut()),
				kernel32::GetLastError() as c_int
			)
		};

		if comm_handle == INVALID_HANDLE_VALUE {
			Err(system_to_io_err("Open port", err))
		} else {
			let mut conn = Connection{ comm_handle: comm_handle };
			let mut dcb = match conn.get_comm_state() {
				Ok(dcb) => dcb,
				Err(e) => return Err(e)
			};

			dcb.BaudRate = baud_rate;
			dcb.ByteSize = 8;
			dcb.StopBits = ONESTOPBIT;
			dcb.Parity = NOPARITY;
			dcb.set_dtr_control(DTR_CONTROL::ENABLE);

			conn.set_comm_state(dcb)
				.and_then(|_| {
					unsafe { PurgeComm(conn.comm_handle, PURGE_RXCLEAR | PURGE_TXCLEAR); }
					conn.set_timeout(40)
				})
				.and_then(|_| Ok(conn))
		}
	}

	/// Retrieve the current control settings for this communications device
	fn get_comm_state(&mut self) -> io::Result<DCB> {
		let mut dcb = unsafe { mem::zeroed() };
		let (succeded, err) = unsafe { (
			GetCommState(self.comm_handle, &mut dcb) != 0,
			kernel32::GetLastError() as i32
		)};

		if succeded {
			Ok(dcb)
		} else {
			Err(system_to_io_err("GetCommState", err))
		}
	}

	/// Configures this communications device according to specifications in a device-control block,
	/// `dcb`.
	fn set_comm_state(&mut self, mut dcb: DCB) -> io::Result<()> {
		let (succeded, err) = unsafe { (
			SetCommState(self.comm_handle, &mut dcb) != 0,
			kernel32::GetLastError() as i32
		)};

		if succeded {
			Ok(())
		} else {
			Err(system_to_io_err("SetCommState", err))
		}
	}

	/// Set interval and total timeouts to `timeout_ms`
	pub fn set_timeout(&mut self, timeout_ms: u32) -> io::Result<()> {
		let (succeded, err) = unsafe { (
			SetCommTimeouts(self.comm_handle, &mut COMMTIMEOUTS{
				ReadIntervalTimeout: timeout_ms,
				ReadTotalTimeoutMultiplier: timeout_ms,
				ReadTotalTimeoutConstant: timeout_ms,
				WriteTotalTimeoutMultiplier: timeout_ms,
				WriteTotalTimeoutConstant: timeout_ms,
			}) != 0,
			kernel32::GetLastError() as i32
		)};

		if succeded {
			Ok(())
		} else {
			Err(system_to_io_err("SetCommTimeouts", err))
		}
	}

	// pub fn baud_rate(&self) -> io::Result<u32> {
	// 	self.
	// }

	/// Read into `buf` until `delim` is encountered. Return n.o. bytes read on success,
	/// and an IO error on failure.
	pub fn read_until(&mut self, delim: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
		use std::io::Read;

		let mut byte = [0_u8];
		loop {
			match self.read(&mut byte) {
				Err(e) => return Err(e),
				Ok(0) => { println!("read 0 bytes"); break },
				Ok(_) => (),
			};

			let buf_len = buf.len();
			if byte[0] == delim {
				return Ok(buf_len);
			}

			if buf_len == buf.capacity() {
				buf.reserve(buf_len);
			}
			buf.push(byte[0])
		}

		// Delimiter was not found before end of stream or timeout
		Err(Error::new(ErrorKind::Other, "Delimiter was not found"))
	}

	/// Read until newline. Return n.o. bytes read on success
	pub fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
		self.read_until('\n' as u8, buf)
	}
}
impl io::Read for Connection {
	fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
		if buf.len() == 0 {
			return Ok(0)
		}

		let mut n_bytes_read = 0;
		let (succeded, err) = unsafe { (
			kernel32::ReadFile(self.comm_handle,
				buf.as_mut_ptr() as *mut c_void,
				buf.len() as u32,
				&mut n_bytes_read,
				ptr::null_mut()) != 0,
			kernel32::GetLastError() as c_int
		)};

		if succeded {
			if n_bytes_read == 0 {
				Err(Error::new(ErrorKind::TimedOut, "Operation timed out"))
			} else {
				Ok(n_bytes_read as usize)
			}
		} else {
			Err(system_to_io_err("read", err))
		}
	}
}
impl io::Write for Connection {
	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
		let mut n_bytes_written = 0;

		let (succeded, err) = unsafe { (
			kernel32::WriteFile(self.comm_handle,
				mem::transmute(buf.as_ptr()),
				buf.len() as u32,
				&mut n_bytes_written,
				ptr::null_mut()) != 0,
			kernel32::GetLastError() as c_int
		) };

		if succeded {
			Ok(n_bytes_written as usize)
		} else {
			Err(system_to_io_err("write", err))
		}
	}

	fn flush(&mut self) -> io::Result<()> {
		let (succeded, err) = unsafe { (
			kernel32::FlushFileBuffers(self.comm_handle) != 0,
			kernel32::GetLastError() as c_int
		)};

		if succeded {
			Ok(())
		} else {
			Err(system_to_io_err("flush", err))
		}
	}
}
impl Drop for Connection {
	fn drop(&mut self) {
		let e = unsafe { kernel32::CloseHandle(self.comm_handle) };
		if e == 0 {
			panic!("Drop of Connection failed. CloseHandle gave error 0x{:x}", e)
		}
	}
}
unsafe impl Send for Connection { }

// Some tests requires correct code to be running on connected serial device

// // Should work with any simple echo code on the arduino
// #[test]
// fn echo_test() {
// 	use std::io::Write;
// 	use std::thread;

// 	let port = "COM8";
// 	let baud_rate = 9600_u32;
// 	let mut connection = Connection::new(port, baud_rate).unwrap();
// 	thread::sleep_ms(2000);

// 	for i in 0..20 {
// 		let test_str = format!("One two {}\n", i);

// 		let n_bytes_written = connection.write(test_str.as_bytes());

// 		let mut buffer = Vec::with_capacity(20);

// 		let n_bytes_read = connection.read_line(&mut buffer);
// 		let read_string = String::from_utf8(buffer).unwrap();

// 		println!("Bytes written: {:?}, Bytes read: {:?}, String read: {}",
// 			n_bytes_written, n_bytes_read, read_string);
// 	}
// }

// Colorswirl. Works with arduino running LEDstream
#[test]
fn colorswirl_test() {
	use std::thread;
	use std::io::Write;

	let port = "COM8";
	let baud_rate = 115_200;
	let mut connection = Connection::new(port, baud_rate).unwrap();

	thread::sleep_ms(2000);

	let n_leds = 32;
	let pixel_size = 3;
	let header_size = 6;
	let mut buffer: Vec<u8> = (0..(header_size + n_leds * pixel_size)).map(|_| 0).collect();

	// A special header / magic word is expected by the corresponding LED streaming code
	// running on the Arduino. This only needs to be initialized once because the number of
	// LEDs remains constant:
	buffer[0] = 'A' as u8;                    // Magic word
	buffer[1] = 'd' as u8;
	buffer[2] = 'a' as u8;
	buffer[3] = ((n_leds - 1) >> 8) as u8;    // LED count high byte
	buffer[4] = ((n_leds - 1) & 0xff) as u8;  // LED count low byte
	buffer[5] = buffer[3] ^ buffer[4] ^ 0x55; // Checksum

	let mut main_sin = 0.0_f32;
	let mut main_hue = 0_u16;

	for _ in 0..1_000 {
		let mut internal_sin = main_sin;
		let mut internal_hue = main_hue;

		let (mut r, mut g, mut b): (u8, u8, u8);
		// Start at position 6, after the LED header/magic word
		for i in (6..buffer.len()).step_by(3) {
			// Fixed-point hue-to-RGB conversion.  'internal_hue' is an integer in the
			// range of 0 to 1535, where 0 = red, 256 = yellow, 512 = green, etc.
			// The high byte (0-5) corresponds to the sextant within the color
			// wheel, while the low byte (0-255) is the fractional part between
			// the primary/secondary colors.
			let pri_sec_frac = (internal_hue & 255) as u8;
			match (internal_hue >> 8) % 6 {
				0 => {
					r = 255;
					g = pri_sec_frac;
					b = 0;
				}, 1 => {
					r = 255 - pri_sec_frac;
					g = 255;
					b = 0;
				}, 2 => {
					r = 0;
					g = 255;
					b = pri_sec_frac;
				}, 3 => {
					r = 0;
					g = 255 - pri_sec_frac;
					b = 255;
				}, 4 => {
					r = pri_sec_frac;
					g = 0;
					b = 255;
				}, _ => {
					r = 255;
					g = 0;
					b = 255 - pri_sec_frac;
				}
			}

			// Resulting hue is multiplied by brightness in the range of 0 to 255
			// (0 = off, 255 = brightest).  Gamma corrrection (the 'powf' function
			// here) adjusts the brightness to be more perceptually linear.
			let brightness = (0.5 + internal_sin.sin() * 0.5).powf(2.8);
			buffer[i]     = (r as f32 * brightness) as u8;
			buffer[i + 1] = (g as f32 * brightness) as u8;
			buffer[i + 2] = (b as f32 * brightness) as u8;

			// Each pixel is slightly offset in both hue and brightness
			internal_hue += 40;
			internal_sin += 0.3;
		}

		// Slowly rotate hue and brightness in opposite directions
		main_hue = (main_hue + 4) % 1536;
		main_sin -= 0.03;

		// Issue color data to LEDs
		connection.write(&buffer[..]).unwrap();
		connection.flush().unwrap(); // Not necessary, just testing

		// The arduino can't handle it if we go too fast
		thread::sleep_ms(2);
	}
}<|endoftext|>


<commit_before>//! The fast sweeping method for the computation of the signed distance function in 2D.
//!
//! ## References
//!
//! [1] Zhao, Hongkai A fast sweeping method for eikonal equations. Math. Comp. 74 (2005), no. 250,
//! 603–627.

/// Computes the signed distance function from a line segment given as the _zero_ level set of a
/// linear function on an isosceles right-angle triangle.
///
/// Inputs are `u`, the values at the vertices. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the signed distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(u: [f64; 3]) -> Option<[f64; 3]> {
    let mut u = u;
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for u in u.iter_mut() {
            *u = -*u;
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            // well isn't this ugly
            return match (u[0], u[1], u[2]) {
                (0., 0., 0.) => Some([0., 0., 0.]),
                (_, 0., 0.) => Some([(0.5f64).sqrt(), 0., 0.]),
                (0., _, 0.) => Some([0., 1., 0.]),
                (0., 0., _) => Some([0., 0., 1.]),
                (0., _, _) => Some([0., 1., 1.]),
                (_, 0., _) => Some([1., 0., (2f64).sqrt()]),
                (_, _, 0.) => Some([1., (2f64).sqrt(), 0.]),
                _ => None,
            };
        } else {
            // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. {
                // 0
                return Some([u[0] / g_norm, i12, 1. - i02]);
            } else if gx > -gy {
                // 1
                return Some([i02, u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i02, i12, -u[2] / g_norm]);
            }
        }
    } else {
        // u[1] < 0.
        if u[2] >= 0. {
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. {
                // 0
                return Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12]);
            } else if -gx > gy {
                // 1
                return Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i01, i12, u[2] / g_norm]);
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            return Some([u[0] / g_norm, i10, i20]);
        }
    }
}

/// Initializes distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it stores the distance
/// to the _zero_ level set in the nodes of triangles through which the level set passes. Stores
/// the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for i in 0..d.len() {
        d[i] = std::f64::MAX;
    }

    for j in 1..ny {
        for i in 1..nx {
            let s = j * nx + i;
            let r = triangle_dist([u[s - nx - 1], u[s - nx], u[s - 1]]);
            if let Some(e) = r {
                d[s - nx - 1] = e[0].min(d[s - nx - 1]);
                d[s - nx] = e[1].min(d[s - nx]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - nx], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - nx] = e[1].min(d[s - nx]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the Fast Sweeping algorithm.
///
/// `d` should be initialized to large values at the unknown nodes.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    for k in 1..5 {
        for q in 0..ny {
            let j = match k {
                3 | 4 => ny - 1 - q,
                _ => q,
            };
            for p in 0..nx {
                let i = match k {
                    2 | 3 => nx - 1 - p,
                    _ => p,
                };
                let s = j * nx + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == nx - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + nx]
                } else if j == ny - 1 {
                    d[s - nx]
                } else {
                    d[s - nx].min(d[s + nx])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

/// Computes the signed distance from the _zero_ level set of the function given by the values of
/// `u` on a regular grid of dimensions `dim` and stores the result to a preallocated array `d`.
///
/// `h` is the distance between neighboring nodes.
///
/// Returns `std::f64::MAX` if all `u` are positive (`-std::f64::MAX` if all `u` are negative).
pub fn signed_distance(d: &mut [f64], u: &[f64], dim: (usize, usize), h: f64) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());
    init_dist(d, u, dim);
    fast_sweep_dist(d, dim);

    for i in 0..d.len() {
        if u[i] < 0. {
            d[i] = -d[i] * h;
        } else {
            d[i] *= h;
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    extern crate ndarray;
    use self::quickcheck::quickcheck;
    use self::ndarray::prelude::*;
    use self::ndarray::Si;

    fn check_line(gx: f64, gy: f64, c: f64, n: usize, tol: f64, print: bool) -> bool {
        let xs = OwnedArray::linspace(0., 1., n);
        let ys = OwnedArray::linspace(0., 1., n);
        let u_array = {
            let mut u_array = xs.broadcast((n, n)).unwrap().to_owned();
            u_array.zip_mut_with(&ys.broadcast((n, n)).unwrap().t(),
                                 |x, y| *x = *x * gx + *y * gy + c);
            u_array
        };
        let u = u_array.as_slice().unwrap();

        let d = {
            let mut d = vec![0f64; n * n];
            signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
            OwnedArray::from_shape_vec((n, n), d).unwrap()
        };
        if print {
            println!("{}", u_array);
            println!("{}", d);
        }
        d.all_close(&u_array, tol)
    }

    #[test]
    fn it_works_for_x_axis_line() {
        fn prop(y: f64) -> bool {
            check_line(0., 1., -((y - y.floor()) * 0.9 + 0.05), 9, 0.00001, false)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_y_axis_line() {
        fn prop(x: f64) -> bool {
            check_line(1., 0., -((x - x.floor()) * 0.9 + 0.05), 9, 0.00001, false)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_diagonal() {
        assert!(check_line((0.5f64).sqrt(),
                           (0.5f64).sqrt(),
                           -(0.5f64).sqrt(),
                           9,
                           1e-6,
                           false));
        assert!(check_line(-(0.5f64).sqrt(), (0.5f64).sqrt(), 0., 9, 1e-6, false));
    }

    #[test]
    fn it_preserves_lines() {
        fn prop(ta: f64) -> bool {
            let n = 17;
            let ta = (ta - ta.floor()) * 2. * ::std::f64::consts::PI;
            let (gy, gx) = ta.sin_cos();
            let c = -(gx + gy) * 0.5;

            let xs = OwnedArray::linspace(0., 1., n);
            let ys = OwnedArray::linspace(0., 1., n);
            let u_array = {
                let mut u_array = xs.broadcast((n, n)).unwrap().to_owned();
                u_array.zip_mut_with(&ys.broadcast((n, n)).unwrap().t(),
                                     |x, y| *x = *x * gx + *y * gy + c);
                u_array
            };
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];
                signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d).unwrap()
            };
            let d2 = {
                let mut d2 = vec![0f64; n * n];
                signed_distance(&mut d2, d.as_slice().unwrap(), (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d2).unwrap()
            };
            // check only elements away from the boundary
            let s = &[Si(2, Some(-2), 1), Si(2, Some(-2), 1)];
            d.slice(s).all_close(&d2.slice(s), 0.001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_is_nonnegative_on_triangle() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }

    #[test]
    fn simple_triangles() {
        assert_eq!(triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(triangle_dist([-1., 0., 0.]),
                   Some([(0.5f64).sqrt(), 0., 0.]));
        assert_eq!(triangle_dist([0., 1., 0.]), Some([0., 1., 0.]));
        assert_eq!(triangle_dist([0., -1., -1.]), Some([0., 1., 1.]));
        assert_eq!(triangle_dist([0., 1., 1.]), Some([0., 1., 1.]));
        assert_eq!(triangle_dist([1., 1., 0.]), Some([1., (2f64).sqrt(), 0.]));
    }
}
<commit_msg>Run clippy<commit_after>//! The fast sweeping method for the computation of the signed distance function in 2D.
//!
//! ## References
//!
//! [1] Zhao, Hongkai A fast sweeping method for eikonal equations. Math. Comp. 74 (2005), no. 250,
//! 603–627.

/// Computes the signed distance function from a line segment given as the _zero_ level set of a
/// linear function on an isosceles right-angle triangle.
///
/// Inputs are `u`, the values at the vertices. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the signed distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(u: [f64; 3]) -> Option<[f64; 3]> {
    let mut u = u;
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for u in &mut u {
            *u = -*u;
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            // well isn't this ugly
            match (u[0], u[1], u[2]) {
                (0., 0., 0.) => Some([0., 0., 0.]),
                (_, 0., 0.) => Some([(0.5f64).sqrt(), 0., 0.]),
                (0., _, 0.) => Some([0., 1., 0.]),
                (0., 0., _) => Some([0., 0., 1.]),
                (0., _, _) => Some([0., 1., 1.]),
                (_, 0., _) => Some([1., 0., (2f64).sqrt()]),
                (_, _, 0.) => Some([1., (2f64).sqrt(), 0.]),
                _ => None,
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. {
                // 0
                Some([u[0] / g_norm, i12, 1. - i02])
            } else if gx > -gy {
                // 1
                Some([i02, u[1] / g_norm, (2f64).sqrt() - i12])
            } else {
                // 2
                Some([i02, i12, -u[2] / g_norm])
            }
        }
    } else if u[2] >= 0. { // u[1] < 0.
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. {
                // 0
                Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12])
            } else if -gx > gy {
                // 1
                Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12])
            } else {
                // 2
                Some([i01, i12, u[2] / g_norm])
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            Some([u[0] / g_norm, i10, i20])
        }

}

/// Initializes distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it stores the distance
/// to the _zero_ level set in the nodes of triangles through which the level set passes. Stores
/// the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    for j in 1..ny {
        for i in 1..nx {
            let s = j * nx + i;
            let r = triangle_dist([u[s - nx - 1], u[s - nx], u[s - 1]]);
            if let Some(e) = r {
                d[s - nx - 1] = e[0].min(d[s - nx - 1]);
                d[s - nx] = e[1].min(d[s - nx]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - nx], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - nx] = e[1].min(d[s - nx]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the Fast Sweeping algorithm.
///
/// `d` should be initialized to large values at the unknown nodes.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    for k in 1..5 {
        for q in 0..ny {
            let j = match k {
                3 | 4 => ny - 1 - q,
                _ => q,
            };
            for p in 0..nx {
                let i = match k {
                    2 | 3 => nx - 1 - p,
                    _ => p,
                };
                let s = j * nx + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == nx - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + nx]
                } else if j == ny - 1 {
                    d[s - nx]
                } else {
                    d[s - nx].min(d[s + nx])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

/// Computes the signed distance from the _zero_ level set of the function given by the values of
/// `u` on a regular grid of dimensions `dim` and stores the result to a preallocated array `d`.
///
/// `h` is the distance between neighboring nodes.
///
/// Returns `std::f64::MAX` if all `u` are positive (`-std::f64::MAX` if all `u` are negative).
pub fn signed_distance(d: &mut [f64], u: &[f64], dim: (usize, usize), h: f64) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());
    init_dist(d, u, dim);
    fast_sweep_dist(d, dim);

    for i in 0..d.len() {
        if u[i] < 0. {
            d[i] = -d[i] * h;
        } else {
            d[i] *= h;
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    extern crate ndarray;
    use self::quickcheck::quickcheck;
    use self::ndarray::prelude::*;
    use self::ndarray::Si;

    fn check_line(gx: f64, gy: f64, c: f64, n: usize, tol: f64, print: bool) -> bool {
        let xs = OwnedArray::linspace(0., 1., n);
        let ys = OwnedArray::linspace(0., 1., n);
        let u_array = {
            let mut u_array = xs.broadcast((n, n)).unwrap().to_owned();
            u_array.zip_mut_with(&ys.broadcast((n, n)).unwrap().t(),
                                 |x, y| *x = *x * gx + *y * gy + c);
            u_array
        };
        let u = u_array.as_slice().unwrap();

        let d = {
            let mut d = vec![0f64; n * n];
            signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
            OwnedArray::from_shape_vec((n, n), d).unwrap()
        };
        if print {
            println!("{}", u_array);
            println!("{}", d);
        }
        d.all_close(&u_array, tol)
    }

    #[test]
    fn it_works_for_x_axis_line() {
        fn prop(y: f64) -> bool {
            check_line(0., 1., -((y - y.floor()) * 0.9 + 0.05), 9, 0.00001, false)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_y_axis_line() {
        fn prop(x: f64) -> bool {
            check_line(1., 0., -((x - x.floor()) * 0.9 + 0.05), 9, 0.00001, false)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_works_for_diagonal() {
        assert!(check_line((0.5f64).sqrt(),
                           (0.5f64).sqrt(),
                           -(0.5f64).sqrt(),
                           9,
                           1e-6,
                           false));
        assert!(check_line(-(0.5f64).sqrt(), (0.5f64).sqrt(), 0., 9, 1e-6, false));
    }

    #[test]
    fn it_preserves_lines() {
        fn prop(ta: f64) -> bool {
            let n = 17;
            let ta = (ta - ta.floor()) * 2. * ::std::f64::consts::PI;
            let (gy, gx) = ta.sin_cos();
            let c = -(gx + gy) * 0.5;

            let xs = OwnedArray::linspace(0., 1., n);
            let ys = OwnedArray::linspace(0., 1., n);
            let u_array = {
                let mut u_array = xs.broadcast((n, n)).unwrap().to_owned();
                u_array.zip_mut_with(&ys.broadcast((n, n)).unwrap().t(),
                                     |x, y| *x = *x * gx + *y * gy + c);
                u_array
            };
            let u = u_array.as_slice().unwrap();

            let d = {
                let mut d = vec![0f64; n * n];
                signed_distance(&mut d, &u, (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d).unwrap()
            };
            let d2 = {
                let mut d2 = vec![0f64; n * n];
                signed_distance(&mut d2, d.as_slice().unwrap(), (n, n), 1. / (n - 1) as f64);
                OwnedArray::from_shape_vec((n, n), d2).unwrap()
            };
            // check only elements away from the boundary
            let s = &[Si(2, Some(-2), 1), Si(2, Some(-2), 1)];
            d.slice(s).all_close(&d2.slice(s), 0.001)
        }
        quickcheck(prop as fn(f64) -> bool);
    }

    #[test]
    fn it_is_nonnegative_on_triangle() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }

    #[test]
    fn simple_triangles() {
        assert_eq!(triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(triangle_dist([-1., 0., 0.]),
                   Some([(0.5f64).sqrt(), 0., 0.]));
        assert_eq!(triangle_dist([0., 1., 0.]), Some([0., 1., 0.]));
        assert_eq!(triangle_dist([0., -1., -1.]), Some([0., 1., 1.]));
        assert_eq!(triangle_dist([0., 1., 1.]), Some([0., 1., 1.]));
        assert_eq!(triangle_dist([1., 1., 0.]), Some([1., (2f64).sqrt(), 0.]));
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

pub struct Slide<T: Iterator, A> {
  iter: T,
  n: uint,
  window: Vec
}

macro_rules! return_if(
  ($cond:expr, $value:expr) => (
    if $cond {
      return $value;
    }
  );
)

impl<A: Clone, T: Iterator> Slide<T, A> {
  fn push_window(&mut self) -> bool {
    let iter_next = self.iter.next();

    if iter_next.is_some() {
      self.window.push(iter_next.unwrap());
      true
    } else {
      false
    }
  }

  fn new(iter: T, n: uint) -> Slide<T, A> {
    Slide{
      iter: iter,
      n: n,
      window: vec![]
    }
  }
}

impl<A: Clone, T: Iterator> Iterator<Vec> for Slide<T, A> {
  fn next(&mut self) -> Option<Vec> {
    if self.n == 0 {
      return None
    }

    return_if!(!self.push_window(), None);

    loop {
      let window_status = self.window.len().cmp(&self.n);

      match window_status {
        Greater => { self.window.remove(0); }
        Equal => { return Some(self.window.clone()); }
        Less => { return_if!(!self.push_window(), None); }
      }
    }
  }
}

#[test]
fn test_slide() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 3);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3])
  assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4])
  assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_equal_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 5);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_zero_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 0);
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_overlong_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 7);
  assert!(slide_iter.next().is_none())
}
<commit_msg>Use Vec::with_capacity to create the window on Slide::new<commit_after>#![feature(macro_rules)]

pub struct Slide<T: Iterator, A> {
  iter: T,
  n: uint,
  window: Vec
}

macro_rules! return_if(
  ($cond:expr, $value:expr) => (
    if $cond {
      return $value;
    }
  );
)

impl<A: Clone, T: Iterator> Slide<T, A> {
  fn push_window(&mut self) -> bool {
    let iter_next = self.iter.next();

    if iter_next.is_some() {
      self.window.push(iter_next.unwrap());
      true
    } else {
      false
    }
  }

  fn new(iter: T, n: uint) -> Slide<T, A> {
    Slide{
      iter: iter,
      n: n,
      window: Vec::with_capacity(n)
    }
  }
}

impl<A: Clone, T: Iterator> Iterator<Vec> for Slide<T, A> {
  fn next(&mut self) -> Option<Vec> {
    if self.n == 0 {
      return None
    }

    return_if!(!self.push_window(), None);

    loop {
      let window_status = self.window.len().cmp(&self.n);

      match window_status {
        Greater => { self.window.remove(0); }
        Equal => { return Some(self.window.clone()); }
        Less => { return_if!(!self.push_window(), None); }
      }
    }
  }
}

#[test]
fn test_slide() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 3);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3])
  assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4])
  assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_equal_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 5);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_zero_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 0);
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_overlong_window() {
  let mut slide_iter = Slide::new(vec![1i, 2, 3, 4, 5].into_iter(), 7);
  assert!(slide_iter.next().is_none())
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use std::str::{MaybeOwned, Slice, Owned};
use std::fmt::Show;
use std::io::util::NullReader;
use time::{Tm, strptime};
use conduit::Request;
use middleware::Middleware;

type Response = Result<conduit::Response, Box<Show + 'static>>;

pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            conduit::Get | conduit::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.pop_equiv(&"Content-Type");
                    res.headers.pop_equiv(&"Content-Length");
                    res.body = box NullReader as Box<Reader + Send>;
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.find_equiv(&"ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.find_equiv(&"Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> MaybeOwned<'a> {
    if header.len() == 1 {
        Slice(header[0])
    } else {
        Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> MaybeOwned<'a> {
    if header.len() == 1 {
        Slice(header[0].as_slice())
    } else {
        Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, String> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, String> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, String> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::fmt::Show;
    use std::io::MemReader;
    use std::collections::HashMap;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning(
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    )

    macro_rules! request(
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(conduit::Get, "/");
            $(req.header($header, $value.to_string());)+
            req
        })
    )

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z");
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Show>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Show>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (uint, &'static str), response: Result<Response, Box<Show>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (uint, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Show + 'static>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: box MemReader::new(self.body.to_string().into_bytes()) as Box<Reader + Send>
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT")
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(macro_rules)]

extern crate time;
extern crate conduit;
extern crate "conduit-middleware" as middleware;

use std::str::{MaybeOwned, Slice, Owned};
use std::fmt::Show;
use std::io::util::NullReader;
use time::{Tm, strptime, ParseError};
use conduit::Request;
use middleware::Middleware;

type Response = Result<conduit::Response, Box<Show + 'static>>;

pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            conduit::Get | conduit::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.pop_equiv(&"Content-Type");
                    res.headers.pop_equiv(&"Content-Length");
                    res.body = box NullReader as Box<Reader + Send>;
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(none_match, res);
    });

    success
}

fn etag_matches<S: Str>(none_match: S, res: &conduit::Response) -> bool {
    res.headers.find_equiv(&"ETag").map(|etag| {
        res_header_val(etag).as_slice() == none_match.as_slice()
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.find_equiv(&"Last-Modified").and_then(|last_modified| {
        parse_http_date(res_header_val(last_modified).as_slice()).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> MaybeOwned<'a> {
    if header.len() == 1 {
        Slice(header[0])
    } else {
        Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> MaybeOwned<'a> {
    if header.len() == 1 {
        Slice(header[0].as_slice())
    } else {
        Owned(header.concat())
    }
}

fn parse_http_date<S: Str>(string: S) -> Result<Tm, ()> {
    let string = string.as_slice();

    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use std::fmt::Show;
    use std::io::MemReader;
    use std::collections::HashMap;
    use time;
    use time::Tm;
    use conduit;
    use conduit::{Request, Response, Handler};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning(
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    )

    macro_rules! request(
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(conduit::Get, "/");
            $(req.header($header, $value.to_string());)+
            req
        })
    )

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        ) as &mut conduit::Request));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z");
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        ) as &mut conduit::Request));
    }

    fn expect_304(response: Result<Response, Box<Show>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body.as_slice(), "");
    }

    fn expect_200(response: Result<Response, Box<Show>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (uint, &'static str), response: Result<Response, Box<Show>>) {
        let mut response = response.ok().expect("No response");
        let body = response.body.read_to_string().ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body.as_slice(), "hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (uint, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Show + 'static>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: box MemReader::new(self.body.to_string().into_bytes()) as Box<Reader + Send>
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap()
    }
}
<|endoftext|>