<commit_before>//#![crate_name="celix_rust"]
//#![feature(libc)]
#![allow(non_camel_case_types,non_snake_case)]

//! A bundle to test Celix and Rust interaction.
//!
//! TODO: Allow more Rust like usage, preferably through use as (more optimised) library.

extern crate libc;
use libc::{c_void,malloc};

use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::mem::size_of;
use std::default::Default;

extern crate celix;
// #[macro_use]
// mod celix;
use celix::{celix_status_t,bundle_context_pt,CELIX_SUCCESS};
//const CELIX_SUCCESS: celix_status_t = 0;

// manifest!(SYMBOLIC_NAME = rust_celix);

/// Default thread count
const DEFAULT_THREADS: u64 = 4;

/// Data to be sent between Celix and this code.
///
/// `tx` is used to control the main worker thread: by sending `()`, the thread will stop.
#[repr(C)]
#[derive(Clone)]
pub struct uData {
	t1: i32,
	t2: i32,
	/// A `Sender` for closing the worker thread (cannot drop a dereference of a raw pointer safely!)
	tx: Option<Sender<()>>,
	work: *const Fn() -> i32
}

impl uData {
	pub fn work() {
		println!("Worker function called");
	}
}

impl Default for uData {
	fn default() -> uData {
		uData {
			t1:0,
			t2:0,
			tx:None,
			work:&(||{0})
		}
	}
}

impl fmt::Debug for uData {
	/// Allows formatting
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "
uData {{
	t1: {:?},
	t2: {:?}
}}", self.t1, self.t2)
	}
}

fn blah() -> i32 {
	println!("Working...");
	0
}

/// Create this bundle
#[no_mangle]
#[allow(unused_variables)]
// pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData: *mut *mut c_void) -> celix_status_t {
// 	println!("create rust");
// 	// println!("{}", SYMBOLIC_NAME);
// 	unsafe {
// 		*userData = malloc(size_of::<uData>()); // C style malloc because the function receives a pointer
// 		(*(*userData as *mut uData)).t1 = 12;
// 		(*(*userData as *mut uData)).t2 = 100;
// 		(*(*userData as *mut uData)).work = & (|| { println!("Working..."); 0 });
// 		(*(*userData as *mut uData)).work = &blah; // Both approaches work
// 	}
// 	CELIX_SUCCESS
// }

pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData:*mut *mut c_void ) -> celix_status_t {
	println!("create rust");
	let mut d = uData {
		t1: 12,
		t2: 100,
		tx: None,
		work: &blah,
	};
	unsafe { (*userData) = d as *mut _ as *mut c_void; }
	CELIX_SUCCESS
}

/// Start this bundle.
///
/// Create the main worker thread, and let that create it's own child threads.
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_start(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("start rust");
	let d : *mut uData;
	d = userData as *mut uData;
	println!("casted d");
	unsafe {
		println!("{:?}", (*d));
		let (tx, rx) = mpsc::channel();
		println!("created channel");
		(*d).tx = Some(tx); // This seems to cause a SIGTRAP without compiler optimisations, will eventually have to find out why
		println!("assigned channel tx");
		(*(*d).work)();
		thread::spawn(move ||{
			println!("started thread");
			// Aditional threads should be created here to allow proper control over them.
			let (ltx,lrx) = mpsc::channel();
			let mut threads = vec![];
			let NTHREADS: u64 = match std::env::var("RUST_THREADS") {
				Ok(s) => match s.parse::<u64>() {
					Ok(i) => i,
					Err(_) => DEFAULT_THREADS,
				},
				Err(_) => DEFAULT_THREADS,
			};

			for i in 0..NTHREADS { // in a..b, b is exclusive, so 0..2 == [0,1]
				let ltx = ltx.clone();
				threads.push(thread::spawn(move || {
					loop {
						match ltx.send(()) {
							Err(SendError) => { // lrx has been dropped, so time to stop this thread
								println!("Stopping worker thread {}", i);
								return;
							},
							Ok(_) => {
								println!("worker thread {} working...", i);
								thread::sleep(Duration::new(0,100));
							},
						}
					}
				}));
			}
			loop {
				match rx.try_recv() {
					Ok(_)|Err(mpsc::TryRecvError::Disconnected) => {
						drop(lrx);
						for t in threads {
							let _ = t.join();
							println!("thread stopped");
						}
						println!("Terminated main worker thread");
						return;
					},
					Err(mpsc::TryRecvError::Empty) => {
						// println!("Working...");
						// thread::sleep(Duration::new(1,0));
					},
				}
			}
		});
	}
	println!("Hello {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Stop this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_stop(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("stop rust");
	let d : *const uData;
	d = userData as *const uData;
	unsafe {
		println!("{:?}", (*d));
		(*(*d).work)();
		match (*d).tx {
			Some(ref tx) => match tx.send(()) {
				Ok(_) => println!("Sent kill signal to worker thread..."),
				Err(_) => println!("Failed to send kill signal to worker thread..."),
			},
			None => panic!("Channel hasn't been created yet!"),
		}
	}
	println!("Goodbye {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Destroy this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_destroy(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("destroy rust");
	CELIX_SUCCESS
}
<commit_msg>Fixed!<commit_after>//#![crate_name="celix_rust"]
//#![feature(libc)]
#![allow(non_camel_case_types,non_snake_case)]

//! A bundle to test Celix and Rust interaction.
//!
//! TODO: Allow more Rust like usage, preferably through use as (more optimised) library.

extern crate libc;
use libc::{c_void,malloc};

use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::mem::size_of;
use std::default::Default;

extern crate celix;
// #[macro_use]
// mod celix;
use celix::{celix_status_t,bundle_context_pt,CELIX_SUCCESS};
//const CELIX_SUCCESS: celix_status_t = 0;

// manifest!(SYMBOLIC_NAME = rust_celix);

/// Default thread count
const DEFAULT_THREADS: u64 = 4;

/// Data to be sent between Celix and this code.
///
/// `tx` is used to control the main worker thread: by sending `()`, the thread will stop.
#[repr(C)]
#[derive(Clone)]
pub struct uData {
	t1: i32,
	t2: i32,
	/// A `Sender` for closing the worker thread (cannot drop a dereference of a raw pointer safely!)
	tx: Option<Sender<()>>,
	work: *const Fn() -> i32
}

impl uData {
	pub fn work() {
		println!("Worker function called");
	}
}

impl Default for uData {
	fn default() -> uData {
		uData {
			t1:0,
			t2:0,
			tx:None,
			work:&(||{0})
		}
	}
}

impl fmt::Debug for uData {
	/// Allows formatting
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "
uData {{
	t1: {:?},
	t2: {:?}
}}", self.t1, self.t2)
	}
}

fn blah() -> i32 {
	println!("Working...");
	0
}

/// Create this bundle
#[no_mangle]
#[allow(unused_variables)]
// pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData: *mut *mut c_void) -> celix_status_t {
// 	println!("create rust");
// 	// println!("{}", SYMBOLIC_NAME);
// 	unsafe {
// 		*userData = malloc(size_of::<uData>()); // C style malloc because the function receives a pointer
// 		(*(*userData as *mut uData)).t1 = 12;
// 		(*(*userData as *mut uData)).t2 = 100;
// 		(*(*userData as *mut uData)).work = & (|| { println!("Working..."); 0 });
// 		(*(*userData as *mut uData)).work = &blah; // Both approaches work
// 	}
// 	CELIX_SUCCESS
// }

pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData:*mut *mut c_void ) -> celix_status_t {
	println!("create rust");
	let d = Box::into_raw(Box::new(uData {
		t1: 12,
		t2: 100,
		tx: None,
		work: &blah,
	}));
	unsafe { (*userData) = d as *mut c_void; }
	CELIX_SUCCESS
}

/// Start this bundle.
///
/// Create the main worker thread, and let that create it's own child threads.
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_start(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("start rust");
	let d : *mut uData;
	d = userData as *mut uData;
	println!("casted d");
	unsafe {
		println!("{:?}", (*d));
		let (tx, rx) = mpsc::channel();
		println!("created channel");
		(*d).tx = Some(tx); // This seems to cause a SIGTRAP without compiler optimisations, will eventually have to find out why
		println!("assigned channel tx");
		(*(*d).work)();
		thread::spawn(move ||{
			println!("started thread");
			// Aditional threads should be created here to allow proper control over them.
			let (ltx,lrx) = mpsc::channel();
			let mut threads = vec![];
			let NTHREADS: u64 = match std::env::var("RUST_THREADS") {
				Ok(s) => match s.parse::<u64>() {
					Ok(i) => i,
					Err(_) => DEFAULT_THREADS,
				},
				Err(_) => DEFAULT_THREADS,
			};

			for i in 0..NTHREADS { // in a..b, b is exclusive, so 0..2 == [0,1]
				let ltx = ltx.clone();
				threads.push(thread::spawn(move || {
					loop {
						match ltx.send(()) {
							Err(SendError) => { // lrx has been dropped, so time to stop this thread
								println!("Stopping worker thread {}", i);
								return;
							},
							Ok(_) => {
								println!("worker thread {} working...", i);
								thread::sleep(Duration::new(0,100));
							},
						}
					}
				}));
			}
			loop {
				match rx.try_recv() {
					Ok(_)|Err(mpsc::TryRecvError::Disconnected) => {
						drop(lrx);
						for t in threads {
							let _ = t.join();
							println!("thread stopped");
						}
						println!("Terminated main worker thread");
						return;
					},
					Err(mpsc::TryRecvError::Empty) => {
						// println!("Working...");
						// thread::sleep(Duration::new(1,0));
					},
				}
			}
		});
	}
	println!("Hello {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Stop this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_stop(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("stop rust");
	let d : *const uData;
	d = userData as *const uData;
	unsafe {
		println!("{:?}", (*d));
		(*(*d).work)();
		match (*d).tx {
			Some(ref tx) => match tx.send(()) {
				Ok(_) => println!("Sent kill signal to worker thread..."),
				Err(_) => println!("Failed to send kill signal to worker thread..."),
			},
			None => panic!("Channel hasn't been created yet!"),
		}
	}
	println!("Goodbye {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Destroy this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_destroy(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("destroy rust");
	CELIX_SUCCESS
}
<|endoftext|>


<commit_before>//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::error::Error;
use std::io;
use std::io::fs::PathExtensions;
use std::os;

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_DATA_HOME").unwrap_or(
        os::homedir().unwrap().join(".local/share")
    )
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> Path {
    get_data_home_from_env(os::getenv)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/usr/local/share:/usr/share".to_string();
    let paths = match getenv("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    os::split_paths(paths)
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<Path> {
    get_data_dirs_from_env(os::getenv)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CONFIG_HOME").unwrap_or(
        os::homedir().unwrap().join(".config")
    )
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> Path {
    get_config_home_from_env(os::getenv)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env(getenv: |&str| -> Option<String>) -> Vec<Path> {
    let default_paths = "/etc/xdg".to_string();
    let paths = match getenv("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    os::split_paths(paths)
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<Path> {
    get_config_dirs_from_env(os::getenv)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env(getenv: |&str| -> Option<String>) -> Path {
    getenv_path(getenv, "XDG_CACHE_HOME").unwrap_or(
        os::homedir().unwrap().join(".cache")
    )
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> Path {
    get_cache_home_from_env(os::getenv)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env(getenv: |&str| -> Option<String>) -> Option<Path> {
    getenv_path(getenv, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<Path> {
    getenv_path(os::getenv, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
pub fn test_runtime_dir(path: &Path) -> Result<(), String> {
    match path.stat() {
        Ok(stat) => {
            if stat.perm.intersects(io::GROUP_RWX | io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

/// Get an environment variable's value as a Path.
fn getenv_path(getenv: |&str| -> Option<String>, env_var: &str) -> Option<Path> {
    let path = getenv(env_var);
    match path {
        Some(path) => {
            let path = Path::new(path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::iter::IteratorExt;
    use std::os;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "".to_string());
        custom_env.insert("XDG_DATA_DIRS", "".to_string());
        custom_env.insert("XDG_CONFIG_HOME", "".to_string());
        custom_env.insert("XDG_CONFIG_DIRS", "".to_string());
        custom_env.insert("XDG_CACHE_HOME", "".to_string());

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = os::make_absolute(&Path::new(".")).unwrap();
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", format!("{}/user/data", cwd.display()));
        custom_env.insert("XDG_DATA_DIRS", format!("{}/share/data:{}/local/data", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CONFIG_HOME", format!("{}/user/config", cwd.display()));
        custom_env.insert("XDG_CONFIG_DIRS", format!("{}/config:{}/local/config", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CACHE_HOME", format!("{}/user/cache", cwd.display()));

        assert!(super::get_data_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_DATA_HOME").map(Path::new).unwrap());
        assert!(super::get_data_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == (os::split_paths(&*custom_env["XDG_DATA_DIRS"])));
        assert!(super::get_config_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CONFIG_HOME").map(Path::new).unwrap());
        assert!(super::get_config_dirs_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == os::split_paths(&*custom_env["XDG_CONFIG_DIRS"]));
        assert!(super::get_cache_home_from_env(|var: &str| { custom_env.get(var).map(|x| x.clone()) })
                == custom_env.get("XDG_CACHE_HOME").map(Path::new).unwrap());
    }
}
<commit_msg>use unboxed closures and fix some formatting<commit_after>//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::error::Error;
use std::io;
use std::io::fs::PathExtensions;
use std::os;

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env<F>(get_env_var: &F) -> Path where
    F: Fn(&str) -> Option<String>
{
    getenv_path(get_env_var, "XDG_DATA_HOME")
        .unwrap_or(os::homedir()
                       .unwrap()
                       .join(".local/share"))
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> Path {
    get_data_home_from_env(&os::getenv)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env<F>(get_env_var: &F) -> Vec<Path> where
    F: Fn(&str) -> Option<String>
{
    let default_paths = "/usr/local/share:/usr/share".to_string();
    let paths = match (*get_env_var)("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    os::split_paths(paths)
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<Path> {
    get_data_dirs_from_env(&os::getenv)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env<F>(get_env_var: &F) -> Path where
    F: Fn(&str) -> Option<String>
{
    getenv_path(get_env_var, "XDG_CONFIG_HOME")
        .unwrap_or(os::homedir()
                       .unwrap()
                       .join(".config"))
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> Path {
    get_config_home_from_env(&os::getenv)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env<F>(get_env_var: &F) -> Vec<Path> where
    F: Fn(&str) -> Option<String>
{
    let default_paths = "/etc/xdg".to_string();
    let paths = match (*get_env_var)("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths.len() > 0 {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    os::split_paths(paths)
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<Path> {
    get_config_dirs_from_env(&os::getenv)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env<F>(get_env_var: &F) -> Path where
    F: Fn(&str) -> Option<String>
{
    getenv_path(get_env_var, "XDG_CACHE_HOME")
        .unwrap_or(os::homedir()
                       .unwrap()
                       .join(".cache"))
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> Path {
    get_cache_home_from_env(&os::getenv)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env<F>(get_env_var: &F) -> Option<Path> where
    F: Fn(&str) -> Option<String>
{
    getenv_path(get_env_var, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<Path> {
    getenv_path(&os::getenv, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
pub fn test_runtime_dir(path: &Path) -> Result<(), String> {
    match path.stat() {
        Ok(stat) => {
            if stat.perm.intersects(io::GROUP_RWX | io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

/// Get an environment variable's value as a Path.
fn getenv_path<F>(get_env_var: &F, env_var: &str) -> Option<Path> where
    F: Fn(&str) -> Option<String>
{
    let path = (*get_env_var)(env_var);
    match path {
        Some(path) => {
            let path = Path::new(path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::os;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "".to_string());

        let f = |&: var: &str| { custom_env.get(var).map(|x| x.clone()) };
        assert!(super::get_data_home_from_env(&f)
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "".to_string());
        custom_env.insert("XDG_DATA_DIRS", "".to_string());
        custom_env.insert("XDG_CONFIG_HOME", "".to_string());
        custom_env.insert("XDG_CONFIG_DIRS", "".to_string());
        custom_env.insert("XDG_CACHE_HOME", "".to_string());

        let f = |&: var: &str| { custom_env.get(var).map(|x| x.clone()) };
        assert!(super::get_data_home_from_env(&f)
                == os::homedir().unwrap().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![Path::new("/usr/local/share"), Path::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == os::homedir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == os::homedir().unwrap().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = os::make_absolute(&Path::new(".")).unwrap();
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", format!("{}/user/data", cwd.display()));
        custom_env.insert("XDG_DATA_DIRS", format!("{}/share/data:{}/local/data", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CONFIG_HOME", format!("{}/user/config", cwd.display()));
        custom_env.insert("XDG_CONFIG_DIRS", format!("{}/config:{}/local/config", cwd.display(), cwd.display()));
        custom_env.insert("XDG_CACHE_HOME", format!("{}/user/cache", cwd.display()));

        let f = |&: var: &str| { custom_env.get(var).map(|x| x.clone()) };
        assert!(super::get_data_home_from_env(&f)
                == custom_env.get("XDG_DATA_HOME").map(Path::new).unwrap());
        assert!(super::get_data_dirs_from_env(&f)
                == (os::split_paths(&*custom_env["XDG_DATA_DIRS"])));
        assert!(super::get_config_home_from_env(&f)
                == custom_env.get("XDG_CONFIG_HOME").map(Path::new).unwrap());
        assert!(super::get_config_dirs_from_env(&f)
                == os::split_paths(&*custom_env["XDG_CONFIG_DIRS"]));
        assert!(super::get_cache_home_from_env(&f)
                == custom_env.get("XDG_CACHE_HOME").map(Path::new).unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate toml;
#[macro_use] extern crate quick_error;

use toml::{Parser, Value, ParserError};
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;

quick_error! {
    #[derive(Debug)]
    pub enum LoadError {
        Io(err: io::Error) {
            from()
        }
        Parse(err: Vec<ParserError>) {
            from()
        }
    }
}

/// Imlements helper functions for loading and parsing .toml files
pub struct Loader;

impl Loader {
    /// Create Toml::Value from file specified by path
    ///
    /// # Example
    /// ```no_run
    /// use toml_loader::Loader;
    /// use std::path::Path;
    ///
    /// let toml = Loader::from_file(Path::new("some.toml")).unwrap();
    /// ```
    pub fn from_file(path: &Path) -> Result<Value, LoadError> {
       let mut f = try!(File::open(path));
       let mut s = String::new();
       try!(f.read_to_string(&mut s));
       let mut parser = Parser::new(&s);
       let res = try!(parser.parse().map(Value::Table).ok_or(parser.errors));
       Ok(res)
    }
}

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

    use super::Loader;
    use self::tempfile::NamedTempFile;
    use std::io::Write;
    use std::path::Path;

    macro_rules! tmp_toml_file {
        ($content:expr) => {
            {
                let mut f = NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[test]
    fn loads_valid_toml_single() {
        let f = tmp_toml_file!("a = 1");
        Loader::from_file(f.path()).unwrap();
    }

    #[test]
    #[should_panic]
    fn fails_to_load_invalid_toml_single() {
        let f = tmp_toml_file!("a - 1");
        Loader::from_file(f.path()).unwrap();
    }

    #[test]
    #[should_panic]
    fn fails_to_load_non_existing_file() {
        // Path "?\0" is invalid on both windows and linux (windows can't have ? and unix can't have \0)
        Loader::from_file(Path::new("?\0")).unwrap();
    }
}
<commit_msg>Add documentation to LoadError<commit_after>extern crate toml;
#[macro_use] extern crate quick_error;

use toml::{Parser, Value, ParserError};
use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;

quick_error! {
    /// Wraps all errors this library can produce
    #[derive(Debug)]
    pub enum LoadError {
        /// IO Error
        Io(err: io::Error) {
            from()
        }
        /// TOML parsing error
        Parse(err: Vec<ParserError>) {
            from()
        }
    }
}

/// Imlements helper functions for loading and parsing .toml files
pub struct Loader;

impl Loader {
    /// Create Toml::Value from file specified by path
    ///
    /// # Example
    /// ```no_run
    /// use toml_loader::Loader;
    /// use std::path::Path;
    ///
    /// let toml = Loader::from_file(Path::new("some.toml")).unwrap();
    /// ```
    pub fn from_file(path: &Path) -> Result<Value, LoadError> {
       let mut f = try!(File::open(path));
       let mut s = String::new();
       try!(f.read_to_string(&mut s));
       let mut parser = Parser::new(&s);
       let res = try!(parser.parse().map(Value::Table).ok_or(parser.errors));
       Ok(res)
    }
}

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

    use super::Loader;
    use self::tempfile::NamedTempFile;
    use std::io::Write;
    use std::path::Path;

    macro_rules! tmp_toml_file {
        ($content:expr) => {
            {
                let mut f = NamedTempFile::new().unwrap();
                f.write_all($content.as_bytes()).unwrap();
                f.flush().unwrap();
                f
            }
        }
    }

    #[test]
    fn loads_valid_toml_single() {
        let f = tmp_toml_file!("a = 1");
        Loader::from_file(f.path()).unwrap();
    }

    #[test]
    #[should_panic]
    fn fails_to_load_invalid_toml_single() {
        let f = tmp_toml_file!("a - 1");
        Loader::from_file(f.path()).unwrap();
    }

    #[test]
    #[should_panic]
    fn fails_to_load_non_existing_file() {
        // Path "?\0" is invalid on both windows and linux (windows can't have ? and unix can't have \0)
        Loader::from_file(Path::new("?\0")).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Functions to find the difference between two texts (strings).
//! Usage
//! ----------
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! difference = "0.4"
//! ```
//!
//! Now you can use the crate in your code
//!
//! ```ignore
//! extern crate difference;
//! ```

#![crate_name = "difference"]
#![doc(html_root_url = "https://johannhof.github.io/difference.rs/")]

// I can basically feel the karma already
#![deny(missing_docs)]

mod lcs;
mod merge;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String),
}

/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
/// use difference::diff;
/// use difference::Difference;
///
/// let (dist, changeset) = diff("test", "tent", "");
///
/// assert_eq!(changeset, vec![
///     Difference::Same("te".to_string()),
///     Difference::Rem("s".to_string()),
///     Difference::Add("n".to_string()),
///     Difference::Same("t".to_string())
/// ]);
/// ```
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let (dist, common) = lcs(orig, edit, split);
    (dist, merge(orig, edit, &common, split))
}

/// Assert the difference between two strings. Works like diff, but takes
/// a fourth parameter that is the expected edit distance (e.g. 0 if you want to
/// test for equality).
///
/// Remember that edit distance might not be equal to your understanding of difference,
/// for example the words "Rust" and "Dust" have an edit distance of 2 because two changes (a
/// removal and an addition) are required to make them look the same.
///
/// Will print an error with a colorful diff using `print_diff` in case of failure.
pub fn assert_diff(orig: &str, edit: &str, split: &str, expected: i32) {
    let (d, _) = diff(orig, edit, split);
    if d != expected {
        print_diff(orig, edit, split);
        panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \
                diffset above",
               orig,
               edit,
               d,
               expected)
    }
}

/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use difference::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let (_, changeset) = diff(orig, edit, split);
    let mut ret = String::new();

    for seq in changeset {
        match seq {
            Difference::Same(ref x) => {
                ret.push_str(x);
                ret.push_str(split);
            }
            Difference::Add(ref x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str(split);
            }
            Difference::Rem(ref x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str(split);
            }
        }
    }
    println!("{}", ret);
}

#[test]
fn test_diff() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    let (dist, changeset) = diff(text1, text2, "\n");

    assert_eq!(dist, 4);

    assert_eq!(changeset,
               vec![Difference::Same("Roses are red, violets are blue,".to_string()),
                    Difference::Rem("I wrote this library,".to_string()),
                    Difference::Add("I wrote this documentation,".to_string()),
                    Difference::Same("just for you.".to_string()),
                    Difference::Rem("(It's true).".to_string()),
                    Difference::Add("(It's quite true).".to_string())]);
}

#[test]
#[should_panic]
fn test_assert_diff_panic() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    assert_diff(text1, text2, "\n'", 0);
}

#[test]
fn test_assert_diff() {
    let text1 = "Roses are red, violets are blue";

    let text2 = "Roses are green, violets are blue";

    assert_diff(text1, text2, " ", 2);
}
<commit_msg>Replace the assert_diff fn with a macro<commit_after>//! Functions to find the difference between two texts (strings).
//! Usage
//! ----------
//!
//! Add the following to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! difference = "0.4"
//! ```
//!
//! Now you can use the crate in your code
//!
//! ```ignore
//! extern crate difference;
//! ```

#![crate_name = "difference"]
#![doc(html_root_url = "https://johannhof.github.io/difference.rs/")]

// I can basically feel the karma already
#![deny(missing_docs)]

mod lcs;
mod merge;

use lcs::lcs;
use merge::merge;

/// Defines the contents of a changeset
/// Changesets will be delivered in order of appearance in the original string
/// Sequences of the same kind will be grouped into one Difference
#[derive(PartialEq, Debug)]
pub enum Difference {
    /// Sequences that are the same
    Same(String),
    /// Sequences that are an addition (don't appear in the first string)
    Add(String),
    /// Sequences that are a removal (don't appear in the second string)
    Rem(String),
}

/// Calculates the edit distance and the changeset for two given strings.
/// The first string is assumed to be the "original", the second to be an
/// edited version of the first. The third parameter specifies how to split
/// the input strings, leading to a more or less exact comparison.
///
/// Common splits are `""` for char-level, `" "` for word-level and `"\n"` for line-level.
///
/// Outputs the edit distance (how much the two strings differ) and a "changeset", that is
/// a `Vec` containing `Difference`s.
///
/// # Examples
///
/// ```
/// use difference::diff;
/// use difference::Difference;
///
/// let (dist, changeset) = diff("test", "tent", "");
///
/// assert_eq!(changeset, vec![
///     Difference::Same("te".to_string()),
///     Difference::Rem("s".to_string()),
///     Difference::Add("n".to_string()),
///     Difference::Same("t".to_string())
/// ]);
/// ```
pub fn diff(orig: &str, edit: &str, split: &str) -> (i32, Vec<Difference>) {
    let (dist, common) = lcs(orig, edit, split);
    (dist, merge(orig, edit, &common, split))
}

/// Assert the difference between two strings. Works like diff, but takes
/// a fourth parameter that is the expected edit distance (e.g. 0 if you want to
/// test for equality).
///
/// Remember that edit distance might not be equal to your understanding of difference,
/// for example the words "Rust" and "Dust" have an edit distance of 2 because two changes (a
/// removal and an addition) are required to make them look the same.
///
/// Will print an error with a colorful diff using `print_diff` in case of failure.
#[macro_export]
macro_rules! assert_diff {
    ($orig:expr , $edit:expr, $split: expr, $expected: expr) => ({
        let orig = $orig;
        let edit = $edit;

        let (d, _) = $crate::diff(orig, edit, &($split));
        if d != $expected {
            $crate::print_diff(orig, edit, &($split));
            panic!("assertion failed: edit distance between {:?} and {:?} is {} and not {}, see \
                    diffset above",
                   orig,
                   edit,
                   d,
                   &($expected))
        }
    })
}

/// Prints a colorful visual representation of the diff.
/// This is just a convenience function for those who want quick results.
///
/// I recommend checking out the examples on how to build your
/// own diff output.
/// # Examples
///
/// ```
/// use difference::print_diff;
/// print_diff("Diffs are awesome", "Diffs are cool", " ");
/// ```
pub fn print_diff(orig: &str, edit: &str, split: &str) {
    let (_, changeset) = diff(orig, edit, split);
    let mut ret = String::new();

    for seq in changeset {
        match seq {
            Difference::Same(ref x) => {
                ret.push_str(x);
                ret.push_str(split);
            }
            Difference::Add(ref x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str(split);
            }
            Difference::Rem(ref x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str(split);
            }
        }
    }
    println!("{}", ret);
}

#[test]
fn test_diff() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    let (dist, changeset) = diff(text1, text2, "\n");

    assert_eq!(dist, 4);

    assert_eq!(changeset,
               vec![Difference::Same("Roses are red, violets are blue,".to_string()),
                    Difference::Rem("I wrote this library,".to_string()),
                    Difference::Add("I wrote this documentation,".to_string()),
                    Difference::Same("just for you.".to_string()),
                    Difference::Rem("(It's true).".to_string()),
                    Difference::Add("(It's quite true).".to_string())]);
}

#[test]
#[should_panic]
fn test_assert_diff_panic() {
    let text1 = "Roses are red, violets are blue,\n\
                 I wrote this library,\n\
                 just for you.\n\
                 (It's true).";

    let text2 = "Roses are red, violets are blue,\n\
                 I wrote this documentation,\n\
                 just for you.\n\
                 (It's quite true).";

    assert_diff!(text1, text2, "\n'", 0);
}

#[test]
fn test_assert_diff() {
    let text1 = "Roses are red, violets are blue";

    let text2 = "Roses are green, violets are blue";

    assert_diff!(text1, text2, " ", 2);
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod add;
pub use add::*;

pub mod sub;
pub use sub::*;

pub mod mul;
pub use mul::*;

pub mod div;
pub use div::*;

pub mod length;
pub use length::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<commit_msg>updated to lastest rust nightly<commit_after>#![no_std]

extern crate num;

pub mod create;
pub use create::*;

pub mod set;
pub use set::*;

pub mod add;
pub use add::*;

pub mod sub;
pub use sub::*;

pub mod mul;
pub use mul::*;

pub mod div;
pub use div::*;

pub mod length;
pub use length::*;

pub mod misc;
pub use misc::*;

pub mod transform;
pub use transform::*;
<|endoftext|>


<commit_before>#![feature(default_type_params)]
#![feature(slicing_syntax)]
#![feature(associated_types)]
#![feature(old_orphan_check)]

extern crate url;
extern crate openssl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate sha1;

#[cfg(test)]
extern crate test;

pub use socket::WebSocket;
pub use message::{WSMessage, WSStatusCode};

pub mod nonce;
pub mod message;
pub mod stream;
pub mod socket;

<commit_msg>features added<commit_after>#![feature(slicing_syntax)]
#![feature(old_orphan_check)]

extern crate url;
extern crate openssl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate sha1;

#[cfg(test)]
extern crate test;

pub use socket::WebSocket;
pub use message::{WSMessage, WSStatusCode};

pub mod nonce;
pub mod message;
pub mod stream;
pub mod socket;

<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

#[crate_id = "haml#0.0.1"];
#[desc = "haml templating library for Rust"];
#[license = "MIT"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

// allow lints temporary
#[allow(missing_doc)];
#[allow(dead_code)];
#[allow(unused_imports)];
#[warn(non_camel_case_types)];

#[feature(macro_rules)];
#[feature(globs)];

extern crate collections;

pub use format::{HtmlFormat, Xhtml, Html4, Html5};
pub use engine::Engine;

mod testing;
mod format;
mod engine;
mod token;
mod input_reader;
mod lexer;
mod dom_tree;
mod parser;
mod error;
<commit_msg>update to new attribute syntax<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

#[crate_id = "haml#0.0.1"];
#[desc = "haml templating library for Rust"];
#[license = "MIT"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

// allow lints temporary
#![allow(missing_doc)]
#![allow(dead_code)]
#![allow(unused_imports)]
#![warn(non_camel_case_types)]

#![feature(macro_rules)]
#![feature(globs)]

extern crate collections;

pub use format::{HtmlFormat, Xhtml, Html4, Html5};
pub use engine::Engine;

mod testing;
mod format;
mod engine;
mod token;
mod input_reader;
mod lexer;
mod dom_tree;
mod parser;
mod error;
<|endoftext|>


<commit_before>/*!

**useful functions for working with frame-rates, sample-rates,
other rates,
time durations,
frequencies, etc and for keeping a constant framerate.**

`rate`, `sample rate`, `frame rate`, `fps`, `frequency`, etc
express the same concept and are therefore used interchangeably.

you can use hertz to compute the time resolution
and frequency range of that can be meaningfully analyzed by a
[short-time fourier transform](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation)
of a signal:

```
extern crate hertz;

fn main() {
    let sample_rate = 44100;
    let window_size = 4096;
    let step_size = 512;

    // 11 hertz is the maximum frequency that can be meaningfully analyzed
    assert_eq!(
        11.,
        hertz::rayleigh(sample_rate as f64, window_size as f64).round());

    // 22050 hertz is the maximum frequency that can be meaningfully analyzed
    assert_eq!(
        22050.,
        hertz::nyquist(sample_rate as f64).round());

    // 12 ms is the time resolution we get when analyzing a 44100 hertz
    // signal with a step size of 512
    assert_eq!(
        12.,
        hertz::s_to_ms(hertz::cycles_per_second_to_seconds_per_cycle(
            sample_rate as f64,
            step_size as f64)).round());
}
```

you can use hertz to keep a constant framerate in a game or other
computer graphics application:

```no_run
fn main() {
    let frames_per_second: usize = 60;

    loop {
        let ns_at_frame_start = hertz::current_time_ns();

        // here's where logic and rendering would go.
        // this is never called more than frames_per_second
        // times per second.

        hertz::sleep_for_constant_rate(
            frames_per_second, ns_at_frame_start);
    }
}
```
*/

extern crate time;

use std::ops::{Mul, Div, Range};

/// nanoseconds to seconds
#[inline]
pub fn ns_to_s(ns: u64) -> f64 {
    (ns as f64) / 1_000_000_000.
}

/// seconds to nanoseconds
#[inline]
pub fn s_to_ns(s: f64) -> f64 {
    s * 1_000_000_000.
}

/// nanoseconds to milliseconds
#[inline]
pub fn ns_to_ms(ns: u64) -> f64 {
    (ns as f64) / 1_000_000.
}

/// seconds to milliseconds
#[inline]
pub fn s_to_ms<T>(s: T) -> T
    where T: Mul<T, Output=T> + From<u16>
{
    s * T::from(1000 as u16)
}

#[test]
fn test_s_to_ms() {
    assert_eq!(s_to_ms(1), 1000);
    assert_eq!(s_to_ms(1.), 1000.);
}

/// milliseconds to seconds
#[inline]
pub fn ms_to_s<T>(ms: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    ms / T::from(1000 as u16)
}

#[test]
fn test_ms_to_s() {
    assert_eq!(ms_to_s(1000), 1);
    assert_eq!(ms_to_s(1000.), 1.);
}

/// milliseconds to nanoseconds
#[inline]
pub fn ms_to_ns(ns: f64) -> f64 {
    ns * 1_000_000.
}

/// when given frames per second (or sample rate)
/// returns the duration of a single frame
#[inline]
pub fn fps_to_ns_per_frame(fps: usize) -> u64 {
    (s_to_ns(1.0) / (fps as f64)).round() as u64
}

/// returns the current timestamp in nanoseconds
#[inline]
pub fn current_time_ns() -> u64 {
    time::precise_time_ns()
}

// /// returns the nanoseconds of sleep which are needed to keep a constant
// /// frame rate
// pub fn ns_sleep_needed_for_constant_rate(fps: usize, ns_at_last_frame_start: u64) -> u64 {

/// useful for keeping a constant framerate
pub fn sleep_for_constant_rate(fps: usize, ns_at_last_frame_start: u64) {
    let ns_per_frame = fps_to_ns_per_frame(fps);
    let ns_after: u64 = time::precise_time_ns();
    let ns_elapsed = ns_after - ns_at_last_frame_start;
    if ns_elapsed < ns_per_frame {
        let ns_left_to_sleep = (ns_per_frame - ns_elapsed) as u32;
        let duration = std::time::Duration::new(0, ns_left_to_sleep);
        std::thread::sleep(duration);
    }
}

/// frequency range that can be modeled when taking the short
/// time fourier transform of a signal with `sample_rate` with
/// a sliding window of `window_sizew`.
/// equivalent to `rayleigh(sample_rate, window_size)..nyquist(sample_rate)`
/// increase the window size to increase the lower frequency
/// increase the sample rate to increase the upper frequency
pub fn hertz_range<T>(sample_rate: T, window_size: T) -> Range<T>
    where T: Div<T, Output=T> + From<u16> + Clone
{
    rayleigh(sample_rate.clone(), window_size)..nyquist(sample_rate)
}

#[test]
fn test_hertz_range() {
    assert_eq!(
        hertz_range(44100., 1024. * 8.),
        (5.38330078125)..22050.);
    assert_eq!(
        hertz_range(44100., 1024. * 4.),
        (10.7666015625)..22050.);
    assert_eq!(
        hertz_range(44100., 1024.),
        (43.06640625)..22050.);
    assert_eq!(
        hertz_range(44100., 512.),
        (86.1328125)..22050.);
}

/// maximum frequency in hertz that can be meaningfully analyzed with a given sample rate
/// [https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation)
pub fn nyquist<T>(sample_rate: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    sample_rate / T::from(2 as u16)
}

#[test]
fn test_nyquist() {
    assert_eq!(nyquist(44100.), 22050.);
}

/// minimum frequency in hertz that can be meaningfully analyzed with a given sample rate and
/// window size
/// [https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Rayleigh_frequency](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Rayleigh_frequency)
pub fn rayleigh<T>(sample_rate: T, window_size: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    T::from(1 as u16) / cycles_per_second_to_seconds_per_cycle(sample_rate, window_size)
}

#[test]
fn test_rayleigh() {
    assert_eq!(rayleigh(44100., 1024.), 43.06640625);
}

/// window duration in seconds
/// sample_rate in hertz
pub fn cycles_per_second_to_seconds_per_cycle<T>(cycles_per_second: T, cycles: T) -> T
    where T: Div<T, Output=T>
{
    cycles / cycles_per_second
}

#[test]
fn test_seconds_per_window() {
    // 11ms time resolution
    assert_eq!(cycles_per_second_to_seconds_per_cycle(44100., 512.), 0.011609977324263039);
    assert_eq!(cycles_per_second_to_seconds_per_cycle(44100., 1024.), 0.023219954648526078);
}
<commit_msg>fix typo in docs<commit_after>/*!

**useful functions for working with frame-rates, sample-rates,
other rates,
time durations,
frequencies, etc and for keeping a constant framerate.**

`rate`, `sample rate`, `frame rate`, `fps`, `frequency`, etc
express the same concept and are therefore used interchangeably.

you can use hertz to compute the time resolution
and frequency range that can be meaningfully analyzed by a
[short-time fourier transform](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation)
of a signal:

```
extern crate hertz;

fn main() {
    let sample_rate = 44100;
    let window_size = 4096;
    let step_size = 512;

    // 11 hertz is the maximum frequency that can be meaningfully analyzed
    assert_eq!(
        11.,
        hertz::rayleigh(sample_rate as f64, window_size as f64).round());

    // 22050 hertz is the maximum frequency that can be meaningfully analyzed
    assert_eq!(
        22050.,
        hertz::nyquist(sample_rate as f64).round());

    // 12 ms is the time resolution we get when analyzing a 44100 hertz
    // signal with a step size of 512
    assert_eq!(
        12.,
        hertz::s_to_ms(hertz::cycles_per_second_to_seconds_per_cycle(
            sample_rate as f64,
            step_size as f64)).round());
}
```

you can use hertz to keep a constant framerate in a game or other
computer graphics application:

```no_run
fn main() {
    let frames_per_second: usize = 60;

    loop {
        let ns_at_frame_start = hertz::current_time_ns();

        // here's where logic and rendering would go.
        // this is never called more than frames_per_second
        // times per second.

        hertz::sleep_for_constant_rate(
            frames_per_second, ns_at_frame_start);
    }
}
```
*/

extern crate time;

use std::ops::{Mul, Div, Range};

/// nanoseconds to seconds
#[inline]
pub fn ns_to_s(ns: u64) -> f64 {
    (ns as f64) / 1_000_000_000.
}

/// seconds to nanoseconds
#[inline]
pub fn s_to_ns(s: f64) -> f64 {
    s * 1_000_000_000.
}

/// nanoseconds to milliseconds
#[inline]
pub fn ns_to_ms(ns: u64) -> f64 {
    (ns as f64) / 1_000_000.
}

/// seconds to milliseconds
#[inline]
pub fn s_to_ms<T>(s: T) -> T
    where T: Mul<T, Output=T> + From<u16>
{
    s * T::from(1000 as u16)
}

#[test]
fn test_s_to_ms() {
    assert_eq!(s_to_ms(1), 1000);
    assert_eq!(s_to_ms(1.), 1000.);
}

/// milliseconds to seconds
#[inline]
pub fn ms_to_s<T>(ms: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    ms / T::from(1000 as u16)
}

#[test]
fn test_ms_to_s() {
    assert_eq!(ms_to_s(1000), 1);
    assert_eq!(ms_to_s(1000.), 1.);
}

/// milliseconds to nanoseconds
#[inline]
pub fn ms_to_ns(ns: f64) -> f64 {
    ns * 1_000_000.
}

/// when given frames per second (or sample rate)
/// returns the duration of a single frame
#[inline]
pub fn fps_to_ns_per_frame(fps: usize) -> u64 {
    (s_to_ns(1.0) / (fps as f64)).round() as u64
}

/// returns the current timestamp in nanoseconds
#[inline]
pub fn current_time_ns() -> u64 {
    time::precise_time_ns()
}

// /// returns the nanoseconds of sleep which are needed to keep a constant
// /// frame rate
// pub fn ns_sleep_needed_for_constant_rate(fps: usize, ns_at_last_frame_start: u64) -> u64 {

/// useful for keeping a constant framerate
pub fn sleep_for_constant_rate(fps: usize, ns_at_last_frame_start: u64) {
    let ns_per_frame = fps_to_ns_per_frame(fps);
    let ns_after: u64 = time::precise_time_ns();
    let ns_elapsed = ns_after - ns_at_last_frame_start;
    if ns_elapsed < ns_per_frame {
        let ns_left_to_sleep = (ns_per_frame - ns_elapsed) as u32;
        let duration = std::time::Duration::new(0, ns_left_to_sleep);
        std::thread::sleep(duration);
    }
}

/// frequency range that can be modeled when taking the short
/// time fourier transform of a signal with `sample_rate` with
/// a sliding window of `window_sizew`.
/// equivalent to `rayleigh(sample_rate, window_size)..nyquist(sample_rate)`
/// increase the window size to increase the lower frequency
/// increase the sample rate to increase the upper frequency
pub fn hertz_range<T>(sample_rate: T, window_size: T) -> Range<T>
    where T: Div<T, Output=T> + From<u16> + Clone
{
    rayleigh(sample_rate.clone(), window_size)..nyquist(sample_rate)
}

#[test]
fn test_hertz_range() {
    assert_eq!(
        hertz_range(44100., 1024. * 8.),
        (5.38330078125)..22050.);
    assert_eq!(
        hertz_range(44100., 1024. * 4.),
        (10.7666015625)..22050.);
    assert_eq!(
        hertz_range(44100., 1024.),
        (43.06640625)..22050.);
    assert_eq!(
        hertz_range(44100., 512.),
        (86.1328125)..22050.);
}

/// maximum frequency in hertz that can be meaningfully analyzed with a given sample rate
/// [https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Explanation)
pub fn nyquist<T>(sample_rate: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    sample_rate / T::from(2 as u16)
}

#[test]
fn test_nyquist() {
    assert_eq!(nyquist(44100.), 22050.);
}

/// minimum frequency in hertz that can be meaningfully analyzed with a given sample rate and
/// window size
/// [https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Rayleigh_frequency](https://en.wikipedia.org/wiki/Short-time_Fourier_transform#Rayleigh_frequency)
pub fn rayleigh<T>(sample_rate: T, window_size: T) -> T
    where T: Div<T, Output=T> + From<u16>
{
    T::from(1 as u16) / cycles_per_second_to_seconds_per_cycle(sample_rate, window_size)
}

#[test]
fn test_rayleigh() {
    assert_eq!(rayleigh(44100., 1024.), 43.06640625);
}

/// window duration in seconds
/// sample_rate in hertz
pub fn cycles_per_second_to_seconds_per_cycle<T>(cycles_per_second: T, cycles: T) -> T
    where T: Div<T, Output=T>
{
    cycles / cycles_per_second
}

#[test]
fn test_seconds_per_window() {
    // 11ms time resolution
    assert_eq!(cycles_per_second_to_seconds_per_cycle(44100., 512.), 0.011609977324263039);
    assert_eq!(cycles_per_second_to_seconds_per_cycle(44100., 1024.), 0.023219954648526078);
}
<|endoftext|>


<commit_before>use std::io::IoResult;

/// A wrapper around any struct implementing the `Reader` trait, additionally
/// allowing for `peek` operations to be performed. Therefore, the
/// `PeekableReader` struct also implements the `Reader` trait.
///
/// The primary invariant of the `PeekableReader` is that after calling the
/// `peek` method, the next `read_byte` call will return the same result as
/// the `peek` does. When the result is a byte (read off the wrapped reader),
/// any read-type method of the `Reader` trait will include the byte as the
/// first one. On the other hand, if the result is an `IoError`, the error
/// will be returned regardless of which read-type method of the `Reader` is
/// invoked. Consecutive `peek`s before any read-type operation is used
/// always return the same `IoResult`.
pub struct PeekableReader<R> {
    inner: R,
    peeked_result: Option<IoResult<u8>>,
}

impl<R: Reader> PeekableReader<R> {
    /// Initializes a new `PeekableReader` which wraps the given underlying
    /// reader.
    pub fn new(reader: R) -> PeekableReader<R> {
        PeekableReader {
            inner: reader,
            peeked_result: None,
        }
    }

    /// Returns the `IoResult` which the Reader will return on the next
    /// `get_byte` call.
    ///
    /// If the `IoResult` is indeed an `IoError`, the error will be returned
    /// for any subsequent read operation invoked upon the `Reader`.
    pub fn peek_byte(&mut self) -> IoResult<u8> {
        // Return either the currently cached peeked byte or obtain a new one
        // from the underlying reader.
        match self.peeked_result {
            Some(ref old_res) => old_res.clone(),
            None => {
                // First get the result of the read from the underlying reader
                self.peeked_result = Some(self.inner.read_byte());

                // Now just return that
                self.peeked_result.clone().unwrap()
            }
        }
    }
}

impl<R: Reader> Reader for PeekableReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        if buf.len() == 0 {
            return Ok(0);
        }

        // First, put the byte that was read off the underlying reader in a
        // (possible) previous peek operation (if such a byte is indeed cached)
        let offset = match self.peeked_result.clone() {
            Some(Err(e)) => {
                self.peeked_result = None;
                return Err(e);
            },
            Some(Ok(b)) => {
                buf[0] = b;
                self.peeked_result = None;
                1
            },
            None => 0,
        };

        if offset == 1 && buf.len() == 1 {
            // We've filled the buffer by using the previously peeked byte
            Ok(1)
        } else {
            // We are still missing more bytes, so we read them from the
            // underlying reader and place them directly in the correct place
            // in the buffer.
            let (_, leftover) = buf.split_at_mut(offset);
            Ok(try!(self.inner.read(leftover)) + offset)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::PeekableReader;
    use std::io::{MemReader, IoError, IoErrorKind, IoResult};

    /// A mock implementation of the `Reader` trait that returns a given
    /// IoError after a certain number of bytes has been read. The error is
    /// returned only once, with subsequent read calls completing successfully
    /// again.
    /// When the Reader successfully reads a byte, it is always `0u8`.
    struct MockReaderWithError {
        error: IoError,
        after: usize,
        bytes_read: usize,
        errored: bool,
    }

    impl MockReaderWithError {
        fn new(error: IoError, after: usize) -> MockReaderWithError {
            MockReaderWithError {
                error: error,
                after: after,
                bytes_read: 0,
                errored: false,
            }
        }
    }

    impl Reader for MockReaderWithError {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
            self.bytes_read += buf.len();
            if self.bytes_read <= self.after || self.errored {
                for b in buf.iter_mut() {
                    *b = 0;
                }

                Ok(buf.len())
            } else {
                self.errored = true;
                Err(self.error.clone())
            }
        }
    }

    /// Helper function which checks whether the given result indicated EOF.
    fn is_eof<T>(res: IoResult<T>) -> bool {
        match res {
            Err(IoError {
                kind: IoErrorKind::EndOfFile,
                ..
            }) => true,
            _ => false,
        }
    }

    /// Helper function which just checks whether the given IoResult is equal
    /// to the given IoError.
    fn is_err<T>(err: &IoError, res: IoResult<T>) -> bool {
        match res {
            Err(ref result_error) => result_error == err,
            _ => false,
        }
    }

    /// Tests that it is possible to invoke the `peek_byte` method multiple
    /// times with the same effect, when there are no intermediate reads.
    #[test]
    fn multiple_peeks_idempotent() {
        let b = 1;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b, b + 1)));

        // The first peek is correct?
        assert_eq!(b, reader.peek_byte().unwrap());
        // The second peek (with no reads in between) still returns the same
        // byte?
        assert_eq!(b, reader.peek_byte().unwrap());
    }

    /// Tests that the `peek_byte` method correctly returns an IoError
    /// returned by the underlying reader on consecutive peek_byte calls.
    #[test]
    fn peek_result_error() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 0));

        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError!");
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too!");
    }

    /// Tests that performing multiple `peek_byte` calls after the `Reader`
    /// has reached EOF always returns EOF.
    #[test]
    fn multiple_peeks_at_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read/skip the first byte
        let _ = reader.read_byte();
        // Consume the EOF (and perform a sanity check that we have reached it)
        assert!(is_eof(reader.read_byte()));

        // All subsequent peeks return EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that peeks and reads correctly work when the underlying reader
    /// only has a single byte.
    #[test]
    fn single_byte_reader_peek() {
        let b = 5u8;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b)));

        // When we peek, we get the correct byte back?
        assert_eq!(b, reader.peek_byte().unwrap());
        // And now we also read it...
        assert_eq!(b, reader.read_byte().unwrap());
        // After this, both the peek and the read return an EOF?
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that peeks and reads from an empty underlying reader instantly
    /// return EOF.
    #[test]
    fn empty_underlying_reader() {
        let mut reader = PeekableReader::new(MemReader::new(vec!()));

        // Must return EOF since the underlying reader is empty
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that when we peek before every read, we correctly end up reading
    /// the entire contents of the underlying Reader.
    #[test]
    fn peek_read_alternate() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.peek_byte().unwrap());
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a peek after the underlying reader has reached EOF fails
    /// with an appropriate error.
    #[test]
    fn peek_after_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read both the only byte from the reader and the EOF
        let _ = reader.read_byte();
        assert!(is_eof(reader.read_byte()));

        // Now the peek still correctly returns the EOF
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that the PeekableReader behaves correctly when only Reader methods
    /// are used.
    #[test]
    fn sequential_reader() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.read_byte()));
        // Still EOF...
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a currently cached peeked byte does not get invalidated when
    /// the read method is invoked with an empty buffer.
    #[test]
    fn zero_length_buffer_read_does_not_invalidate_peek() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));
        let first_peek = reader.peek_byte().unwrap();

        let mut buffer = vec!();
        let _ = reader.read(buffer.as_mut_slice());

        assert_eq!(first_peek, reader.peek_byte().unwrap());
    }

    /// Tests that when the underlying `Reader` returns an IoError, the `peek`
    /// method keeps returning the same error for each call until the error is
    /// actually "read" by the client (by invoking one of the read methods of
    /// the `Reader`).
    #[test]
    fn always_returns_same_io_error_on_peek() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 1));
        // Read the first byte (no error)
        assert_eq!(0, reader.read_byte().unwrap());

        // This peek now signals an IoError
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the first peek");
        // The next peek still reports the same error...
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too");
        // The read also indicates the same error.
        assert!(is_err(&err, reader.read_byte()),
                "Expected an IoError on the read too");
        // The next peek has to retry the read -- which succeeds
        assert_eq!(0, reader.peek_byte().unwrap());
    }

    /// Test for the MockReaderWithError helper mock class...
    #[test]
    fn mock_sanity_check() {
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 1);

            // First byte is not a problem.
            assert_eq!(0, reader.read_byte().unwrap());
            // However, now the read fails...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // But, already on the next one, we're out of the woods.
            assert_eq!(0, reader.read_byte().unwrap());
        }
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 0);

            // The read fails on the first one...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // ...but now we're good.
            assert_eq!(0, reader.read_byte().unwrap());
        }
    }

}
<commit_msg>Replace `split_at_mut` with a range index<commit_after>use std::io::IoResult;

/// A wrapper around any struct implementing the `Reader` trait, additionally
/// allowing for `peek` operations to be performed. Therefore, the
/// `PeekableReader` struct also implements the `Reader` trait.
///
/// The primary invariant of the `PeekableReader` is that after calling the
/// `peek` method, the next `read_byte` call will return the same result as
/// the `peek` does. When the result is a byte (read off the wrapped reader),
/// any read-type method of the `Reader` trait will include the byte as the
/// first one. On the other hand, if the result is an `IoError`, the error
/// will be returned regardless of which read-type method of the `Reader` is
/// invoked. Consecutive `peek`s before any read-type operation is used
/// always return the same `IoResult`.
pub struct PeekableReader<R> {
    inner: R,
    peeked_result: Option<IoResult<u8>>,
}

impl<R: Reader> PeekableReader<R> {
    /// Initializes a new `PeekableReader` which wraps the given underlying
    /// reader.
    pub fn new(reader: R) -> PeekableReader<R> {
        PeekableReader {
            inner: reader,
            peeked_result: None,
        }
    }

    /// Returns the `IoResult` which the Reader will return on the next
    /// `get_byte` call.
    ///
    /// If the `IoResult` is indeed an `IoError`, the error will be returned
    /// for any subsequent read operation invoked upon the `Reader`.
    pub fn peek_byte(&mut self) -> IoResult<u8> {
        // Return either the currently cached peeked byte or obtain a new one
        // from the underlying reader.
        match self.peeked_result {
            Some(ref old_res) => old_res.clone(),
            None => {
                // First get the result of the read from the underlying reader
                self.peeked_result = Some(self.inner.read_byte());

                // Now just return that
                self.peeked_result.clone().unwrap()
            }
        }
    }
}

impl<R: Reader> Reader for PeekableReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        if buf.len() == 0 {
            return Ok(0);
        }

        // First, put the byte that was read off the underlying reader in a
        // (possible) previous peek operation (if such a byte is indeed cached)
        let offset = match self.peeked_result.clone() {
            Some(Err(e)) => {
                self.peeked_result = None;
                return Err(e);
            },
            Some(Ok(b)) => {
                buf[0] = b;
                self.peeked_result = None;
                1
            },
            None => 0,
        };

        if offset == 1 && buf.len() == 1 {
            // We've filled the buffer by using the previously peeked byte
            Ok(1)
        } else {
            // We are still missing more bytes, so we read them from the
            // underlying reader and place them directly in the correct place
            // in the buffer.
            Ok(try!(self.inner.read(&mut buf[offset..])) + offset)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::PeekableReader;
    use std::io::{MemReader, IoError, IoErrorKind, IoResult};

    /// A mock implementation of the `Reader` trait that returns a given
    /// IoError after a certain number of bytes has been read. The error is
    /// returned only once, with subsequent read calls completing successfully
    /// again.
    /// When the Reader successfully reads a byte, it is always `0u8`.
    struct MockReaderWithError {
        error: IoError,
        after: usize,
        bytes_read: usize,
        errored: bool,
    }

    impl MockReaderWithError {
        fn new(error: IoError, after: usize) -> MockReaderWithError {
            MockReaderWithError {
                error: error,
                after: after,
                bytes_read: 0,
                errored: false,
            }
        }
    }

    impl Reader for MockReaderWithError {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
            self.bytes_read += buf.len();
            if self.bytes_read <= self.after || self.errored {
                for b in buf.iter_mut() {
                    *b = 0;
                }

                Ok(buf.len())
            } else {
                self.errored = true;
                Err(self.error.clone())
            }
        }
    }

    /// Helper function which checks whether the given result indicated EOF.
    fn is_eof<T>(res: IoResult<T>) -> bool {
        match res {
            Err(IoError {
                kind: IoErrorKind::EndOfFile,
                ..
            }) => true,
            _ => false,
        }
    }

    /// Helper function which just checks whether the given IoResult is equal
    /// to the given IoError.
    fn is_err<T>(err: &IoError, res: IoResult<T>) -> bool {
        match res {
            Err(ref result_error) => result_error == err,
            _ => false,
        }
    }

    /// Tests that it is possible to invoke the `peek_byte` method multiple
    /// times with the same effect, when there are no intermediate reads.
    #[test]
    fn multiple_peeks_idempotent() {
        let b = 1;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b, b + 1)));

        // The first peek is correct?
        assert_eq!(b, reader.peek_byte().unwrap());
        // The second peek (with no reads in between) still returns the same
        // byte?
        assert_eq!(b, reader.peek_byte().unwrap());
    }

    /// Tests that the `peek_byte` method correctly returns an IoError
    /// returned by the underlying reader on consecutive peek_byte calls.
    #[test]
    fn peek_result_error() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 0));

        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError!");
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too!");
    }

    /// Tests that performing multiple `peek_byte` calls after the `Reader`
    /// has reached EOF always returns EOF.
    #[test]
    fn multiple_peeks_at_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read/skip the first byte
        let _ = reader.read_byte();
        // Consume the EOF (and perform a sanity check that we have reached it)
        assert!(is_eof(reader.read_byte()));

        // All subsequent peeks return EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that peeks and reads correctly work when the underlying reader
    /// only has a single byte.
    #[test]
    fn single_byte_reader_peek() {
        let b = 5u8;
        let mut reader = PeekableReader::new(MemReader::new(vec!(b)));

        // When we peek, we get the correct byte back?
        assert_eq!(b, reader.peek_byte().unwrap());
        // And now we also read it...
        assert_eq!(b, reader.read_byte().unwrap());
        // After this, both the peek and the read return an EOF?
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that peeks and reads from an empty underlying reader instantly
    /// return EOF.
    #[test]
    fn empty_underlying_reader() {
        let mut reader = PeekableReader::new(MemReader::new(vec!()));

        // Must return EOF since the underlying reader is empty
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that when we peek before every read, we correctly end up reading
    /// the entire contents of the underlying Reader.
    #[test]
    fn peek_read_alternate() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.peek_byte().unwrap());
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.peek_byte()));
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a peek after the underlying reader has reached EOF fails
    /// with an appropriate error.
    #[test]
    fn peek_after_eof() {
        let mut reader = PeekableReader::new(MemReader::new(vec!(1)));
        // Read both the only byte from the reader and the EOF
        let _ = reader.read_byte();
        assert!(is_eof(reader.read_byte()));

        // Now the peek still correctly returns the EOF
        assert!(is_eof(reader.peek_byte()));
    }

    /// Tests that the PeekableReader behaves correctly when only Reader methods
    /// are used.
    #[test]
    fn sequential_reader() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));

        for &b in vec.iter() {
            assert_eq!(b, reader.read_byte().unwrap());
        }
        // Now we're at EOF
        assert!(is_eof(reader.read_byte()));
        // Still EOF...
        assert!(is_eof(reader.read_byte()));
    }

    /// Tests that a currently cached peeked byte does not get invalidated when
    /// the read method is invoked with an empty buffer.
    #[test]
    fn zero_length_buffer_read_does_not_invalidate_peek() {
        let vec: Vec<u8> = (0u8..5).collect();
        let mut reader = PeekableReader::new(MemReader::new(vec.clone()));
        let first_peek = reader.peek_byte().unwrap();

        let mut buffer = vec!();
        let _ = reader.read(buffer.as_mut_slice());

        assert_eq!(first_peek, reader.peek_byte().unwrap());
    }

    /// Tests that when the underlying `Reader` returns an IoError, the `peek`
    /// method keeps returning the same error for each call until the error is
    /// actually "read" by the client (by invoking one of the read methods of
    /// the `Reader`).
    #[test]
    fn always_returns_same_io_error_on_peek() {
        let err = IoError {
            kind: IoErrorKind::OtherIoError,
            desc: "Dummy error",
            detail: None,
        };
        let mut reader = PeekableReader::new(
            MockReaderWithError::new(err.clone(), 1));
        // Read the first byte (no error)
        assert_eq!(0, reader.read_byte().unwrap());

        // This peek now signals an IoError
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the first peek");
        // The next peek still reports the same error...
        assert!(is_err(&err, reader.peek_byte()),
                "Expected an IoError on the second peek too");
        // The read also indicates the same error.
        assert!(is_err(&err, reader.read_byte()),
                "Expected an IoError on the read too");
        // The next peek has to retry the read -- which succeeds
        assert_eq!(0, reader.peek_byte().unwrap());
    }

    /// Test for the MockReaderWithError helper mock class...
    #[test]
    fn mock_sanity_check() {
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 1);

            // First byte is not a problem.
            assert_eq!(0, reader.read_byte().unwrap());
            // However, now the read fails...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // But, already on the next one, we're out of the woods.
            assert_eq!(0, reader.read_byte().unwrap());
        }
        {
            let err = IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "Dummy error",
                detail: None,
            };
            let mut reader = MockReaderWithError::new(err.clone(), 0);

            // The read fails on the first one...
            assert!(is_err(&err, reader.read_byte()),
                    "Expected an IoError on the read byte");
            // ...but now we're good.
            assert_eq!(0, reader.read_byte().unwrap());
        }
    }

}
<|endoftext|>


<commit_before>//! # libgoblin
//!
//! ![say the right
//! words](https://s-media-cache-ak0.pinimg.com/736x/1b/6a/aa/1b6aaa2bae005e2fed84b1a7c32ecb1b.jpg)
//!
//! `libgoblin` is a cross-platform trifecta of binary parsing and loading fun.  Currently, it only
//! supports the ELF format, in both 32-bit and 64-bit variants.  The mach parser is in progress, and the PE format will follow.  `libgoblin` is
//! engineered to be tailored towards very different use-case scenarios, for example:
//!
//! * a no-std mode; just simply set default features to false
//! * a endian aware parsing and reading
//! * for binary loaders which don't require this, simply use `elf32` and `elf64` (and `std` of course)
//!
//! # Example Feature Usage
//! For example, if you are writing a 64-bit kernel, or just want a barebones C-like
//! header interface which defines the structures, just select `elf64`, `--cfg
//! feature=\"elf64\"`, which will compile without `std`.
//!
//! Similarly, if you want to use host endianness loading via the various `from_fd` methods, `--cfg
//! feature=\"std\"`, which will not use the `byteorder` extern crate, and read the bytes
//! from disk in the endianness of the host machine.
//!
//! If you want endian aware reading, and you don't use `default`, then you need to opt in as normal
//! via `endian_fd`

#![cfg_attr(not(feature = "std"), no_std)]

// if the no_endian feature flag is set the libary will only be able to
// process files with the same endianess as the machine.
#[cfg(feature = "endian_fd")]
extern crate scroll;

#[cfg(feature = "endian_fd")]
#[macro_use]
extern crate scroll_derive;

#[macro_use]
extern crate quick_error;

#[cfg(feature = "std")]
extern crate core;

#[macro_use]
mod macros;

#[cfg(any(feature = "elf64", feature = "elf32"))]
#[macro_use]
pub mod elf;

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

// if racer gets path understanding, i think this is the way to go; it hides everything from the
// user w.r.t. module internals like _64, etc.  though i did like the more declarative version
// below, without using paths, i just for the life of me cannot get the compiler to reexport values
// two mods down while keeping the internal mod name private... and i don't see anyone else doing
// this
#[cfg(feature = "elf64")]
#[path = "elf/_64/mod.rs"]
pub mod elf64;

#[cfg(feature = "elf32")]
#[path = "elf/_32/mod.rs"]
pub mod elf32;

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

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

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

#[derive(Debug, Default)]
pub struct HintData {
    pub is_lsb: bool,
    pub is_64: Option<bool>,
}

#[derive(Debug)]
pub enum Hint {
    Elf(HintData),
    Mach,
    PE,
    Archive,
    Unknown,
}

/// Peeks at the underlying Read object. Requires the underlying bytes to have at least 16 byte length.
pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> error::Result<Hint> {
    use scroll::Pread;
    use std::io::{SeekFrom};
    let mut bytes = [0u8; 16];
    fd.seek(SeekFrom::Start(0))?;
    fd.read_exact(&mut bytes)?;
    if &bytes[0..elf::header::SELFMAG] == elf::header::ELFMAG {
        let class = bytes[elf::header::EI_CLASS];
        let is_lsb = bytes[elf::header::EI_DATA] == elf::header::ELFDATA2LSB;
        let is_64 =
            if class == elf::header::ELFCLASS64 {
                Some (true)
            } else if class == elf::header::ELFCLASS32 {
                Some (false)
            } else { None };

        Ok(Hint::Elf(HintData { is_lsb: is_lsb, is_64: is_64 }))
    } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
        Ok(Hint::Archive)
    } else if (&bytes[0..2]).pread_into::<u16>(0)? == pe::header::DOS_MAGIC {
        Ok(Hint::PE)
    } else {
        Ok(Hint::Unknown)
    }
}
<commit_msg>goblin: reset seek to 0 because nice<commit_after>//! # libgoblin
//!
//! ![say the right
//! words](https://s-media-cache-ak0.pinimg.com/736x/1b/6a/aa/1b6aaa2bae005e2fed84b1a7c32ecb1b.jpg)
//!
//! `libgoblin` is a cross-platform trifecta of binary parsing and loading fun.  Currently, it only
//! supports the ELF format, in both 32-bit and 64-bit variants.  The mach parser is in progress, and the PE format will follow.  `libgoblin` is
//! engineered to be tailored towards very different use-case scenarios, for example:
//!
//! * a no-std mode; just simply set default features to false
//! * a endian aware parsing and reading
//! * for binary loaders which don't require this, simply use `elf32` and `elf64` (and `std` of course)
//!
//! # Example Feature Usage
//! For example, if you are writing a 64-bit kernel, or just want a barebones C-like
//! header interface which defines the structures, just select `elf64`, `--cfg
//! feature=\"elf64\"`, which will compile without `std`.
//!
//! Similarly, if you want to use host endianness loading via the various `from_fd` methods, `--cfg
//! feature=\"std\"`, which will not use the `byteorder` extern crate, and read the bytes
//! from disk in the endianness of the host machine.
//!
//! If you want endian aware reading, and you don't use `default`, then you need to opt in as normal
//! via `endian_fd`

#![cfg_attr(not(feature = "std"), no_std)]

// if the no_endian feature flag is set the libary will only be able to
// process files with the same endianess as the machine.
#[cfg(feature = "endian_fd")]
extern crate scroll;

#[cfg(feature = "endian_fd")]
#[macro_use]
extern crate scroll_derive;

#[macro_use]
extern crate quick_error;

#[cfg(feature = "std")]
extern crate core;

#[macro_use]
mod macros;

#[cfg(any(feature = "elf64", feature = "elf32"))]
#[macro_use]
pub mod elf;

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

// if racer gets path understanding, i think this is the way to go; it hides everything from the
// user w.r.t. module internals like _64, etc.  though i did like the more declarative version
// below, without using paths, i just for the life of me cannot get the compiler to reexport values
// two mods down while keeping the internal mod name private... and i don't see anyone else doing
// this
#[cfg(feature = "elf64")]
#[path = "elf/_64/mod.rs"]
pub mod elf64;

#[cfg(feature = "elf32")]
#[path = "elf/_32/mod.rs"]
pub mod elf32;

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

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

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

#[derive(Debug, Default)]
pub struct HintData {
    pub is_lsb: bool,
    pub is_64: Option<bool>,
}

#[derive(Debug)]
pub enum Hint {
    Elf(HintData),
    Mach,
    PE,
    Archive,
    Unknown,
}

/// Peeks at the underlying Read object. Requires the underlying bytes to have at least 16 byte length. Resets the seek after reading.
pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> error::Result<Hint> {
    use scroll::Pread;
    use std::io::{SeekFrom};
    let mut bytes = [0u8; 16];
    fd.seek(SeekFrom::Start(0))?;
    fd.read_exact(&mut bytes)?;
    fd.seek(SeekFrom::Start(0))?;
    if &bytes[0..elf::header::SELFMAG] == elf::header::ELFMAG {
        let class = bytes[elf::header::EI_CLASS];
        let is_lsb = bytes[elf::header::EI_DATA] == elf::header::ELFDATA2LSB;
        let is_64 =
            if class == elf::header::ELFCLASS64 {
                Some (true)
            } else if class == elf::header::ELFCLASS32 {
                Some (false)
            } else { None };

        Ok(Hint::Elf(HintData { is_lsb: is_lsb, is_64: is_64 }))
    } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
        Ok(Hint::Archive)
    } else if (&bytes[0..2]).pread_into::<u16>(0)? == pe::header::DOS_MAGIC {
        Ok(Hint::PE)
    } else {
        Ok(Hint::Unknown)
    }
}
<|endoftext|>