<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A bare-metal library supplying functions rustc may lower code to
//!
//! This library is not intended for general use, and is superseded by a system
//! libc if one is available. In a freestanding context, however, common
//! functions such as memset, memcpy, etc are not implemented. This library
//! provides an implementation of these functions which are either required by
//! libcore or called by rustc implicitly.
//!
//! This library is never included by default, and must be manually included if
//! necessary. It is an error to include this library when also linking with
//! the system libc library.

#![no_std]
#![feature(no_std, core)]

// This library defines the builtin functions, so it would be a shame for
// LLVM to optimize these function calls to themselves!
#![no_builtins]

extern crate core;

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

#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                            n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
    if src < dest as *const u8 { // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else { // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    return s;
}

#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32
        }
        i += 1;
    }
    return 0;
}

#[cfg(test)]
mod test {
    use core::str::StrExt;
    use core::slice::SliceExt;

    use super::{memcmp, memset, memcpy, memmove};

    #[test]
    fn memcmp_single_byte_pointers() {
        unsafe {
            assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00);
            assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00);
        }
    }

    #[test]
    fn memcmp_strings() {
        {
            let (x, z) = ("Hello!", "Good Bye.");
            let l = x.len();
            unsafe {
                assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0);
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0);
                assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0);
            }
        }
        {
            let (x, z) = ("hey!", "hey.");
            let l = x.len();
            unsafe {
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0);
            }
        }
    }

    #[test]
    fn memset_single_byte_pointers() {
        let mut x: u8 = 0xFF;
        unsafe {
            memset(&mut x, 0xAA, 1);
            assert_eq!(x, 0xAA);
            memset(&mut x, 0x00, 1);
            assert_eq!(x, 0x00);
            x = 0x01;
            memset(&mut x, 0x12, 0);
            assert_eq!(x, 0x01);
        }
    }

    #[test]
    fn memset_array() {
        let mut buffer = [b'X';  100];
        unsafe {
            memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len());
        }
        for byte in buffer.iter() { assert_eq!(*byte, b'#'); }
    }

    #[test]
    fn memcpy_and_memcmp_arrays() {
        let (src, mut dst) = ([b'X';  100], [b'Y';  100]);
        unsafe {
            assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0);
            let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100);
            assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0);
        }
    }

    #[test]
    fn memmove_overlapping() {
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[4], &buffer[0], 6);
                let mut i = 0;
                for byte in b"0123012345".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[0], &buffer[4], 6);
                let mut i = 0;
                for byte in b"4567896789".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
    }
}
<commit_msg>Fix tests on nightly<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A bare-metal library supplying functions rustc may lower code to
//!
//! This library is not intended for general use, and is superseded by a system
//! libc if one is available. In a freestanding context, however, common
//! functions such as memset, memcpy, etc are not implemented. This library
//! provides an implementation of these functions which are either required by
//! libcore or called by rustc implicitly.
//!
//! This library is never included by default, and must be manually included if
//! necessary. It is an error to include this library when also linking with
//! the system libc library.

#![no_std]
#![feature(no_std, core)]
#![cfg_attr(test, feature(core_str_ext, core_slice_ext))]

// This library defines the builtin functions, so it would be a shame for
// LLVM to optimize these function calls to themselves!
#![no_builtins]

extern crate core;

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

#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                            n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
    if src < dest as *const u8 { // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else { // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    return s;
}

#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32
        }
        i += 1;
    }
    return 0;
}

#[cfg(test)]
mod test {
    use core::str::StrExt;
    use core::slice::SliceExt;

    use super::{memcmp, memset, memcpy, memmove};

    #[test]
    fn memcmp_single_byte_pointers() {
        unsafe {
            assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00);
            assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00);
        }
    }

    #[test]
    fn memcmp_strings() {
        {
            let (x, z) = ("Hello!", "Good Bye.");
            let l = x.len();
            unsafe {
                assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0);
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0);
                assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0);
            }
        }
        {
            let (x, z) = ("hey!", "hey.");
            let l = x.len();
            unsafe {
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0);
            }
        }
    }

    #[test]
    fn memset_single_byte_pointers() {
        let mut x: u8 = 0xFF;
        unsafe {
            memset(&mut x, 0xAA, 1);
            assert_eq!(x, 0xAA);
            memset(&mut x, 0x00, 1);
            assert_eq!(x, 0x00);
            x = 0x01;
            memset(&mut x, 0x12, 0);
            assert_eq!(x, 0x01);
        }
    }

    #[test]
    fn memset_array() {
        let mut buffer = [b'X';  100];
        unsafe {
            memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len());
        }
        for byte in buffer.iter() { assert_eq!(*byte, b'#'); }
    }

    #[test]
    fn memcpy_and_memcmp_arrays() {
        let (src, mut dst) = ([b'X';  100], [b'Y';  100]);
        unsafe {
            assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0);
            let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100);
            assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0);
        }
    }

    #[test]
    fn memmove_overlapping() {
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[4], &buffer[0], 6);
                let mut i = 0;
                for byte in b"0123012345".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[0], &buffer[4], 6);
                let mut i = 0;
                for byte in b"4567896789".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(os, core, old_io, old_path)]

//! 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::old_io as io;
use std::old_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());
    }
}
<commit_msg>Use new split_paths + home_dir<commit_after>#![feature(os, core, old_io, old_path, env)]

//! 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::old_io as io;
use std::old_io::fs::PathExtensions;
use std::os;
use std::env;

/// 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(env::home_dir()
                       .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
    };

    env::split_paths(&paths).collect()
}

/// 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(env::home_dir()
                       .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
    };

    env::split_paths(&paths).collect()
}

/// 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(env::home_dir()
                       .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::env;
    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)
                == env::home_dir().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)
                == env::home_dir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == env::home_dir().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)
                == env::home_dir().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)
                == env::home_dir().unwrap().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![Path::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == env::home_dir().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)
                == (env::split_paths(&*custom_env["XDG_DATA_DIRS"]).collect::<Vec<Path>>()));
        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)
                == env::split_paths(&*custom_env["XDG_CONFIG_DIRS"]).collect::<Vec<Path>>());
        assert!(super::get_cache_home_from_env(&f)
                == custom_env.get("XDG_CACHE_HOME").map(Path::new).unwrap());
    }
}
<|endoftext|>


<commit_before>//! Ethereum devp2p protocol implementation
//!
//! It is layered in the following way:
//! * `RLPxNode` which represents the whole pool of connected peers. It handles message routing and peer management.
//! * `MuxServer` which provides a request-response API to otherwise stateless P2P protocol.
//! * `EthIngressServer` which `MuxServer` calls into when new requests and gossip messages arrive.
//! * `MuxServer` itself implements `EthProtocol` which is a simple gateway to abstract Ethereum network.

#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
#![allow(
    unreachable_code,
    clippy::cast_possible_truncation,
    clippy::default_trait_access,
    clippy::filter_map,
    clippy::if_not_else,
    clippy::missing_errors_doc,
    clippy::module_name_repetitions,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::used_underscore_binding,
    clippy::wildcard_imports
)]

mod disc;
pub mod ecies;
mod errors;
mod eth;
mod mac;
mod mux;
mod node_filter;
mod peer;
mod rlpx;
mod types;
mod util;

pub use disc::*;
pub use eth::{proto as eth_proto, Server as EthServer};
pub use mux::MuxServer;
pub use peer::PeerStream;
pub use rlpx::{ListenOptions, Server as RLPxNode};
pub use types::{
    CapabilityId, CapabilityInfo, CapabilityName, Message, NodeRecord, ProtocolRegistrar,
};
<commit_msg>Export PeerId<commit_after>//! Ethereum devp2p protocol implementation
//!
//! It is layered in the following way:
//! * `RLPxNode` which represents the whole pool of connected peers. It handles message routing and peer management.
//! * `MuxServer` which provides a request-response API to otherwise stateless P2P protocol.
//! * `EthIngressServer` which `MuxServer` calls into when new requests and gossip messages arrive.
//! * `MuxServer` itself implements `EthProtocol` which is a simple gateway to abstract Ethereum network.

#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
#![allow(
    unreachable_code,
    clippy::cast_possible_truncation,
    clippy::default_trait_access,
    clippy::filter_map,
    clippy::if_not_else,
    clippy::missing_errors_doc,
    clippy::module_name_repetitions,
    clippy::too_many_arguments,
    clippy::too_many_lines,
    clippy::used_underscore_binding,
    clippy::wildcard_imports
)]

mod disc;
pub mod ecies;
mod errors;
mod eth;
mod mac;
mod mux;
mod node_filter;
mod peer;
mod rlpx;
mod types;
mod util;

pub use disc::*;
pub use eth::{proto as eth_proto, Server as EthServer};
pub use mux::MuxServer;
pub use peer::PeerStream;
pub use rlpx::{ListenOptions, Server as RLPxNode};
pub use types::{
    CapabilityId, CapabilityInfo, CapabilityName, Message, NodeRecord, PeerId, ProtocolRegistrar,
};
<|endoftext|>


<commit_before>#![crate_type = "rlib"]
#![crate_name = "cripes"]
#![warn(missing_docs)]

#![feature(alloc)]

#![feature(core_intrinsics)]
#![feature(heap_api)]
#![feature(unsize)]
#![feature(coerce_unsized)]
#![feature(drop_in_place)]

extern crate num;
extern crate smallvec;

#[macro_use]
pub mod util;

#[macro_use]
pub mod symbol;
pub mod pattern;
<commit_msg>lib.rs: remove unused feature decl `drop_in_place`<commit_after>#![crate_type = "rlib"]
#![crate_name = "cripes"]
#![warn(missing_docs)]

#![feature(alloc)]

#![feature(core_intrinsics)]
#![feature(heap_api)]
#![feature(unsize)]
#![feature(coerce_unsized)]

extern crate num;
extern crate smallvec;

#[macro_use]
pub mod util;

#[macro_use]
pub mod symbol;
pub mod pattern;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::BufReader;
use std::io::prelude::*;
use std::collections::hash_map::Entry::{Vacant, Occupied};

#[derive(Default)]
pub struct Actor {
    pub request_count: i64,
    pub methods:       HashMap<String, i64>,
    pub responses:     HashMap<String, i64>,
}

struct LogEntry {
    address:  String,
    method:   String,
    response: String,
}

impl LogEntry {
    fn valid(&self) -> bool {
        if self.address.is_empty() || self.method.is_empty() || self.response.is_empty() {
            return false;
        }
        return true;
    }
}

fn create_or_increment(hash: &mut HashMap<String, i64>, key: String) {
    match hash.entry(key) {
        Vacant(e) => { e.insert(1); },
        Occupied(mut e) => { *e.get_mut() += 1 },
    }
}

fn process_line(actors: &mut HashMap<String, Actor>, line: &str) {
    let parts: Vec<&str> = line.split(' ').collect();
    let log_entry = LogEntry { address: parts[0].to_string(), method: parts[5].replace("\"", "").to_string(), response: parts[8].to_string() };
    if log_entry.valid() {
        match actors.entry(log_entry.address) {
            Vacant(key) => {
                let mut actor = Actor { request_count: 1, ..Default::default() };
                actor.methods.insert(log_entry.method, 1);
                actor.responses.insert(log_entry.response, 1);
                key.insert(actor);
            },
            Occupied(mut actor) => {
                actor.get_mut().request_count += 1;
                create_or_increment(&mut actor.get_mut().methods, log_entry.method);
                create_or_increment(&mut actor.get_mut().responses, log_entry.response);
            },
        }
    } else {
        println!("Invalid");
    }
}

pub fn process(logfile: &str) -> Result<HashMap<String, Actor>, String> {
    let path = Path::new(logfile);
    let file_handle = match File::open(&path) {
        Err(why) => {
            return Err(format!("Could not open {} : {}", path.display(), Error::description(&why)));
        },
        Ok(file) => file,
    };

    let reader = BufReader::new(file_handle);
    let mut actors = HashMap::<String, Actor>::new();
    for line in reader.lines() {
        match line {
            Ok(line) => process_line(&mut actors, &line),
            Err(e)   => return Err(format!("ERROR {}", e)),
        }
    }

    return Ok(actors);
}
<commit_msg>Get rid of println! call<commit_after>use std::collections::HashMap;
use std::path::Path;
use std::fs::File;
use std::error::Error;
use std::io::BufReader;
use std::io::prelude::*;
use std::collections::hash_map::Entry::{Vacant, Occupied};

#[derive(Default)]
pub struct Actor {
    pub request_count: i64,
    pub methods:       HashMap<String, i64>,
    pub responses:     HashMap<String, i64>,
}

struct LogEntry {
    address:  String,
    method:   String,
    response: String,
}

impl LogEntry {
    fn valid(&self) -> bool {
        if self.address.is_empty() || self.method.is_empty() || self.response.is_empty() {
            return false;
        }
        return true;
    }
}

fn create_or_increment(hash: &mut HashMap<String, i64>, key: String) {
    match hash.entry(key) {
        Vacant(e) => { e.insert(1); },
        Occupied(mut e) => { *e.get_mut() += 1 },
    }
}

fn process_line(actors: &mut HashMap<String, Actor>, line: &str) {
    let parts: Vec<&str> = line.split(' ').collect();
    let log_entry = LogEntry { address: parts[0].to_string(), method: parts[5].replace("\"", "").to_string(), response: parts[8].to_string() };
    if log_entry.valid() {
        match actors.entry(log_entry.address) {
            Vacant(key) => {
                let mut actor = Actor { request_count: 1, ..Default::default() };
                actor.methods.insert(log_entry.method, 1);
                actor.responses.insert(log_entry.response, 1);
                key.insert(actor);
            },
            Occupied(mut actor) => {
                actor.get_mut().request_count += 1;
                create_or_increment(&mut actor.get_mut().methods, log_entry.method);
                create_or_increment(&mut actor.get_mut().responses, log_entry.response);
            },
        }
    } else {
        //TODO: Do something useful here.
    }
}

pub fn process(logfile: &str) -> Result<HashMap<String, Actor>, String> {
    let path = Path::new(logfile);
    let file_handle = match File::open(&path) {
        Err(why) => {
            return Err(format!("Could not open {} : {}", path.display(), Error::description(&why)));
        },
        Ok(file) => file,
    };

    let reader = BufReader::new(file_handle);
    let mut actors = HashMap::<String, Actor>::new();
    for line in reader.lines() {
        match line {
            Ok(line) => process_line(&mut actors, &line),
            Err(e)   => return Err(format!("ERROR {}", e)),
        }
    }

    return Ok(actors);
}
<|endoftext|>


<commit_before>mod graph;
mod node;
mod edge;

mod matching;

pub fn match_graph(query: graph::Graph, query_root_index: node::Index, graph: graph::Graph) -> bool {
    let query_root_node = &query.nodes[query_root_index];

    let mut graph_root_index: Option<usize> = None;
    for i in 0..graph.nodes.len() {
        if query_root_node.matches(&graph.nodes[i]) {
            graph_root_index = Some(i);
            break;
        }
    }
    if graph_root_index.is_none() { return false; }

    return matching::recusive_node_match(query_root_index, graph_root_index.unwrap(), &query, &graph);
}

pub fn expand_subgraph(graph: &graph::Graph, root_index: node::Index) -> Vec<node::Index> {
    let mut node_list = vec![root_index];
    let connected_nodes: Vec<node::Index> = graph.edges_for_node(root_index).iter().map(|&e| graph.edges[e].target).collect();
    for node in connected_nodes {
        for inner_node in expand_subgraph(graph, node) {
            node_list.push(inner_node);
        }
    }

    return node_list;
}

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

    #[test]
    fn complete_traverse() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(expand_subgraph(&simple_graph, 0), vec![0,1,2]);
    }

    #[test]
    fn incomplete_traverse() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node2, node1, "edge1".to_string(), None);

        assert_eq!(expand_subgraph(&simple_graph, 0), vec![0,1]);
    }

    #[test]
    fn match_complete_graph() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);

        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), None);
        let node1 = query_graph.add_node("node1".to_string(), None);
        let node2 = query_graph.add_node("node2".to_string(), None);
        query_graph.add_edge(node0, node1, "edge0".to_string(), None);
        query_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(match_graph(query_graph, 0, simple_graph), true);
    }

    #[test]
    fn match_subgraph() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        let node3 = simple_graph.add_node("node3".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);
        simple_graph.add_edge(node2, node3, "edge1".to_string(), None);

        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), None);
        let node1 = query_graph.add_node("node1".to_string(), None);
        let node2 = query_graph.add_node("node2".to_string(), None);
        query_graph.add_edge(node0, node1, "edge0".to_string(), None);
        query_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(match_graph(query_graph, 0, simple_graph), true);
    }

    #[test]
    fn fail_to_match() {
        let mut attributes = HashMap::new();
        attributes.insert("key".to_string(), "value".to_string());
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), Some(attributes.clone()));
        let node1 = simple_graph.add_node("node1".to_string(), Some(attributes.clone()));
        simple_graph.add_edge(node0, node1, "edge0".to_string(), Some(attributes.clone()));

        attributes.insert("key2".to_string(), "value2".to_string());
        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), Some(attributes.clone()));
        let node1 = query_graph.add_node("node1".to_string(), Some(attributes.clone()));
        query_graph.add_edge(node0, node1, "edge0".to_string(), Some(attributes.clone()));

        assert_eq!(match_graph(query_graph, 0, simple_graph), false);
    }
}
<commit_msg>Implement basic traversal restriction<commit_after>mod graph;
mod node;
mod edge;

mod matching;

pub fn match_graph(query: graph::Graph, query_root_index: node::Index, graph: graph::Graph) -> bool {
    let query_root_node = &query.nodes[query_root_index];

    let mut graph_root_index: Option<usize> = None;
    for i in 0..graph.nodes.len() {
        if query_root_node.matches(&graph.nodes[i]) {
            graph_root_index = Some(i);
            break;
        }
    }
    if graph_root_index.is_none() { return false; }

    return matching::recusive_node_match(query_root_index, graph_root_index.unwrap(), &query, &graph);
}

pub fn expand_subgraph(
    graph: &graph::Graph, root_index: node::Index, banned_identifiers: &Vec<String>)
    -> Vec<node::Index> {
        let mut node_list = vec![root_index];
        let root_node_edges: Vec<node::Index> = graph.edges_for_node(root_index);
        for edge in root_node_edges {
            if banned_identifiers.contains(&graph.edges[edge].identifier) {
                continue;
            }
            let target = graph.edges[edge].target;
            for inner_node in expand_subgraph(graph, target, &banned_identifiers) {
                node_list.push(inner_node);
            }
        }

        return node_list;
}

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

    #[test]
    fn traversal_simple() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(expand_subgraph(&simple_graph, 0, &vec![]), vec![0,1,2]);
    }

    #[test]
    fn traveral_incomplete() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node2, node1, "edge1".to_string(), None);

        assert_eq!(expand_subgraph(&simple_graph, 0, &vec![]), vec![0,1]);
    }

    #[test]
    fn traveral_restricted() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        let node3 = simple_graph.add_node("node3".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "banned".to_string(), None);
        simple_graph.add_edge(node1, node3, "edge2".to_string(), None);

        assert_eq!(expand_subgraph(&simple_graph, 0, &vec!["banned".to_string()]), vec![0,1,3]);
    }

    #[test]
    fn match_complete_graph() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);

        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), None);
        let node1 = query_graph.add_node("node1".to_string(), None);
        let node2 = query_graph.add_node("node2".to_string(), None);
        query_graph.add_edge(node0, node1, "edge0".to_string(), None);
        query_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(match_graph(query_graph, 0, simple_graph), true);
    }

    #[test]
    fn match_subgraph() {
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), None);
        let node1 = simple_graph.add_node("node1".to_string(), None);
        let node2 = simple_graph.add_node("node2".to_string(), None);
        let node3 = simple_graph.add_node("node3".to_string(), None);
        simple_graph.add_edge(node0, node1, "edge0".to_string(), None);
        simple_graph.add_edge(node1, node2, "edge1".to_string(), None);
        simple_graph.add_edge(node2, node3, "edge1".to_string(), None);

        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), None);
        let node1 = query_graph.add_node("node1".to_string(), None);
        let node2 = query_graph.add_node("node2".to_string(), None);
        query_graph.add_edge(node0, node1, "edge0".to_string(), None);
        query_graph.add_edge(node1, node2, "edge1".to_string(), None);

        assert_eq!(match_graph(query_graph, 0, simple_graph), true);
    }

    #[test]
    fn match_failure() {
        let mut attributes = HashMap::new();
        attributes.insert("key".to_string(), "value".to_string());
        let mut simple_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = simple_graph.add_node("node0".to_string(), Some(attributes.clone()));
        let node1 = simple_graph.add_node("node1".to_string(), Some(attributes.clone()));
        simple_graph.add_edge(node0, node1, "edge0".to_string(), Some(attributes.clone()));

        attributes.insert("key2".to_string(), "value2".to_string());
        let mut query_graph = graph::Graph { nodes: vec![], edges: vec![] };
        let node0 = query_graph.add_node("node0".to_string(), Some(attributes.clone()));
        let node1 = query_graph.add_node("node1".to_string(), Some(attributes.clone()));
        query_graph.add_edge(node0, node1, "edge0".to_string(), Some(attributes.clone()));

        assert_eq!(match_graph(query_graph, 0, simple_graph), false);
    }
}
<|endoftext|>


<commit_before>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[uint], ts: &mut TopologicalSort<uint>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<commit_msg>tsort: Remove `uint` or `int` usage as general integer<commit_after>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<i32>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[i32], ts: &mut TopologicalSort<i32>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<|endoftext|>


<commit_before>pub mod ascii_writer;
pub mod markdown_writer;
pub mod reader;
pub mod writer;

#[derive(Debug, Eq, PartialEq)]
pub struct Table {
  rows: Vec<Vec<String>>,
  has_headers: bool,
}

impl Table {
  pub fn new() -> Self {
    Table::from(vec![], false)
  }

  pub fn with_headers(has_headers: bool) -> Self {
    Table::from(vec![], has_headers)
  }

  pub fn from(rows: Vec<Vec<String>>, has_headers: bool) -> Self {
    Table { rows, has_headers }
  }

  pub fn push_row(&mut self, row: Vec<String>) {
    self.rows.push(row);
  }
}

#[derive(Debug)]
pub struct Error {
  kind: ErrorKind,
}

#[derive(Debug)]
pub enum ErrorKind {
  Read,
  Write,
}

pub trait Read {
  fn read(&mut self) -> Result<Table, Error>;
}

pub trait Write {
  fn write(&self, table: Table) -> Result<(), Error>;
}
<commit_msg>Add column_widths to Table struct<commit_after>use unicode_width::UnicodeWidthStr;

pub mod ascii_writer;
pub mod markdown_writer;
pub mod reader;
pub mod writer;

#[derive(Debug, Eq, PartialEq)]
pub struct Table {
  rows: Vec<Vec<String>>,
  has_headers: bool,
}

impl Table {
  pub fn new() -> Self {
    Table::from(vec![], false)
  }

  pub fn with_headers(has_headers: bool) -> Self {
    Table::from(vec![], has_headers)
  }

  pub fn from(rows: Vec<Vec<String>>, has_headers: bool) -> Self {
    Table { rows, has_headers }
  }

  pub fn push_row(&mut self, row: Vec<String>) {
    self.rows.push(row);
  }

  pub fn column_len(&self) -> usize {
    self.rows.iter().fold(0, |num, row| num.max(row.len()))
  }

  pub fn column_widths(&self) -> Vec<usize> {
    let mut max_widths = vec![0; self.column_len()];

    for row in self.rows.iter() {
      for (i, cell) in row.iter().enumerate() {
        let max_width = max_widths.get(i).unwrap().clone();
        max_widths[i] = max_width.max(UnicodeWidthStr::width(cell as &str));
      }
    }

    max_widths
  }
}

#[derive(Debug)]
pub struct Error {
  kind: ErrorKind,
}

#[derive(Debug)]
pub enum ErrorKind {
  Read,
  Write,
}

pub trait Read {
  fn read(&mut self) -> Result<Table, Error>;
}

pub trait Write {
  fn write(&self, table: Table) -> Result<(), Error>;
}

mod tests {
  #[test]
  fn table_column_len() {
    let test_cases = vec![
      (vec![], 0),
      (vec![vec![]], 0),
      (vec![vec![String::from("alice")]], 1),
      (vec![vec![String::from("alice"), String::from("100")]], 2),
      (
        vec![
          vec![String::from("alice"), String::from("100")],
          vec![String::from("bob")],
        ],
        2,
      ),
    ];

    for test_case in test_cases {
      let table = crate::Table::from(test_case.0, false);
      assert_eq!(table.column_len(), test_case.1);
    }
  }

  #[test]
  fn table_column_widths() {
    let test_cases = vec![
      (vec![], vec![]),
      (vec![vec![]], vec![]),
      (vec![vec![String::from("alice")]], vec![5]),
      (
        vec![vec![String::from("alice"), String::from("80")]],
        vec![5, 2],
      ),
      (
        vec![
          vec![String::from("alice"), String::from("80")],
          vec![String::from("bob"), String::from("100")],
        ],
        vec![5, 3],
      ),
      (
        vec![
          vec![String::from("alice"), String::from("80")],
          vec![String::from("ボブ"), String::from("100点")],
        ],
        vec![5, 5],
      ),
    ];

    for test_case in test_cases {
      let table = crate::Table::from(test_case.0, false);
      assert_eq!(table.column_widths(), test_case.1);
    }
  }
}
<|endoftext|>


<commit_before>//! Atomic counting semaphore that can help you control access to a common resource
//! by multiple processes in a concurrent system.
//!
//! ## Features
//!
//! - Fully lock-free* semantics
//! - Provides RAII-style acquire/release API
//! - Implements `Send`, `Sync` and `Clone`
//!
//! _* when not using the `shutdown` API_

extern crate parking_lot;

use std::ops::Deref;
use std::sync::Arc;

use parking_lot::RwLock;

mod raw;
use raw::RawSemaphore;

#[derive(Debug, PartialEq, Eq)]
/// An error indicating a failure to acquire access to the resource
/// behind the semaphore.
///
/// Returned from `Semaphore::try_access`.
pub enum TryAccessError {
    /// The capacity of the semaphore was exceeded.
    CapacityExceeded,
    /// The semaphore has been shut down.
    Shutdown
}

/// An atomic counter that can help you control shared access to a resource.
pub struct Semaphore<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<RwLock<Option<Arc<T>>>>
}

impl<T> Clone for Semaphore<T> {
    fn clone(&self) -> Semaphore<T> {
        Semaphore {
            raw: self.raw.clone(),
            resource: self.resource.clone()
        }
    }
}

impl<T> Semaphore<T> {
    /// Create a new semaphore around a resource with the given limit.
    pub fn new(limit: usize, resource: T) -> Self {
        Semaphore {
            raw: Arc::new(RawSemaphore::new(limit)),
            resource: Arc::new(RwLock::new(Some(Arc::new(resource))))
        }
    }

    #[inline]
    /// Attempt to access the underlying resource of this semaphore.
    ///
    /// This function will try to acquire access, and then return an RAII
    /// guard structure which will release the access when it falls out of scope.
    ///
    /// If the semaphore is at limit or currently shutting down,
    /// a `TryAccessError` will be returned.
    pub fn try_access(&self) -> Result<Guard<T>, TryAccessError> {
        if let Some(ref resource) = *self.resource.read() {
            if self.raw.try_acquire() {
                let raw_guard = RawGuard(self.raw.clone());
                Ok(Guard { raw: Arc::new(raw_guard), resource: resource.clone() })
            } else {
                Err(TryAccessError::CapacityExceeded)
            }
        } else {
            Err(TryAccessError::Shutdown)
        }
    }

    /// Shut down the semaphore.
    ///
    /// This prevents any further access from being granted to the underlying resource.
    ///
    /// As soon as the last access is released and the returned handle goes out of scope,
    /// the resource will be dropped.
    ///
    /// Does _not_ block until the resource is no longer in use. If you would like to do that,
    /// you can call `wait` on the returned handle.
    pub fn shutdown(&self) -> ShutdownHandle<T> {
        ShutdownHandle {
            raw: self.raw.clone(),
            _resource: self.resource.write().take()
        }
    }
}

/// A handle representing the shutdown process of a semaphore.
pub struct ShutdownHandle<T> {
    raw: Arc<RawSemaphore>,
    _resource: Option<Arc<T>>
}

impl<T> ShutdownHandle<T> {
    /// Block until the resource is not being accessed anymore.
    ///
    /// Please note that this does not take into account any unguarded
    /// references. This means that after the method returned the resource
    /// could still be kept alive by one or more unguarded references.
    pub fn wait(&self) {
        self.raw.wait_until_inactive()
    }

    #[doc(hidden)]
    pub fn is_complete(&self) -> bool {
        !self.raw.is_active()
    }
}

struct RawGuard(Arc<RawSemaphore>);

impl Drop for RawGuard {
    #[inline]
    fn drop(&mut self) {
        self.0.release()
    }
}

/// An RAII guard used to release access to the semaphore automatically when it falls out of scope.
///
/// Guards can be cloned, in which case the original guard and all descendent guards need
/// to go out of scope for the single access to be released on the semaphore.
pub struct Guard<T> {
    raw: Arc<RawGuard>,
    resource: Arc<T>
}

impl<T> Clone for Guard<T> {
    #[inline]
    fn clone(&self) -> Guard<T> {
        Guard { raw: self.raw.clone(), resource: self.resource.clone() }
    }
}

impl<T> Guard<T> {
    #[inline]
    #[deprecated(since="0.2.1", note="please use `Guard::clone` instead")]
    /// Spawns an unguarded reference to the resource.
    pub fn as_unguarded(&self) -> UnguardedRef<T> {
        UnguardedRef { resource: self.resource.clone() }
    }
}

impl<T: Sized> Deref for Guard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

/// An unguarded reference to a resource.
///
/// Can be created via `Guard::as_unguarded`.
///
/// This reference is not tracked by the semaphore around the resource.
/// It can therefore be used in situations where after acquiring access
/// you want to split access to the resource.
///
/// Caution is advised as the existence of unguarded references will cause
/// the resource to be retained, even when the semaphore has fully shut down.
pub struct UnguardedRef<T> {
    resource: Arc<T>
}

impl<T: Sized> Deref for UnguardedRef<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

#[cfg(test)]
mod tests {
    use super::{Semaphore, TryAccessError};

    #[test]
    fn succeeds_to_acquire_when_empty() {
        let sema = Semaphore::new(1, ());
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_full() {
        let sema = Semaphore::new(4, ());
        let guards = (0..4).map(|_| {
            sema.try_access().expect("guard acquisition failed")
        }).collect::<Vec<_>>();
        assert_eq!(sema.try_access().err(), Some(TryAccessError::CapacityExceeded));
        drop(guards);
    }

    #[test]
    fn dropping_guard_frees_capacity() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        drop(guard);
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_shut_down() {
        let sema = Semaphore::new(4, ());
        sema.shutdown();
        assert_eq!(sema.try_access().err(), Some(TryAccessError::Shutdown));
    }

    #[test]
    fn shutdown_complete_when_guard_drops() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        let handle = sema.shutdown();
        assert_eq!(false, handle.is_complete());
        drop(guard);
        assert_eq!(true, handle.is_complete());
    }

    #[test]
    fn shutdown_complete_when_parent_and_child_guards_drop()  {
        let sema = Semaphore::new(1, ());
        let parent_guard = sema.try_access().expect("guard acquisition failed");
        let child_guard = parent_guard.clone();
        let handle = sema.shutdown();
        assert_eq!(false, handle.is_complete());
        drop(parent_guard);
        assert_eq!(false, handle.is_complete());
        drop(child_guard);
        assert_eq!(true, handle.is_complete());
    }
}
<commit_msg>api refactor<commit_after>//! Atomic counting semaphore that can help you control access to a common resource
//! by multiple processes in a concurrent system.
//!
//! ## Features
//!
//! - Fully lock-free* semantics
//! - Provides RAII-style acquire/release API
//! - Implements `Send`, `Sync` and `Clone`
//!
//! _* when not using the `shutdown` API_

extern crate parking_lot;

use std::ops::Deref;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use parking_lot::RwLock;

mod raw;
use raw::RawSemaphore;

/// Result returned from `Semaphore::try_access`.
pub type TryAccessResult<T> = Result<SemaphoreGuard<T>, TryAccessError>;

#[derive(Copy, Clone, Debug, PartialEq)]
/// Error indicating a failure to acquire access to the resource
/// behind the semaphore.
///
/// Returned from `Semaphore::try_access`.
pub enum TryAccessError {
    /// This semaphore has shut down and will no longer grant access to the underlying resource.
    Shutdown,
    /// This semaphore has no more capacity to grant further access.
    /// Other access needs to be released before this semaphore can grant more.
    NoCapacity
}

/// Atomic counter that can help you control shared access to a resource.
pub struct Semaphore<T> {
    raw: Arc<RawSemaphore>,
    resource: Arc<RwLock<Option<Arc<T>>>>
}

impl<T> Clone for Semaphore<T> {
    fn clone(&self) -> Semaphore<T> {
        Semaphore {
            raw: self.raw.clone(),
            resource: self.resource.clone()
        }
    }
}

impl<T> Semaphore<T> {
    /// Create a new semaphore around a resource with the given limit.
    pub fn new(limit: usize, resource: T) -> Self {
        Semaphore {
            raw: Arc::new(RawSemaphore::new(limit)),
            resource: Arc::new(RwLock::new(Some(Arc::new(resource))))
        }
    }

    #[inline]
    /// Attempt to access the underlying resource of this semaphore.
    ///
    /// This function will try to acquire access, and then return an RAII
    /// guard structure which will release the access when it falls out of scope.
    ///
    /// If the semaphore is out of capacity or shut down, a `TryAccessError` will be returned.
    pub fn try_access(&self) -> TryAccessResult<T> {
        if let Some(ref resource) = *self.resource.read() {
            if self.raw.try_acquire() {
                Ok(SemaphoreGuard {
                    raw: self.raw.clone(),
                    counter: Arc::new(AtomicUsize::new(1)),
                    resource: resource.clone()
                })
            } else {
                Err(TryAccessError::NoCapacity)
            }
        } else {
            Err(TryAccessError::Shutdown)
        }
    }

    /// Shut down the semaphore.
    ///
    /// This prevents any further access from being granted to the underlying resource.
    ///
    /// As soon as the last access is released and the returned handle goes out of scope,
    /// the resource will be dropped.
    ///
    /// Does _not_ block until the resource is no longer in use. If you would like to do that,
    /// you can call `wait` on the returned handle.
    pub fn shutdown(&self) -> ShutdownHandle<T> {
        ShutdownHandle {
            raw: self.raw.clone(),
            resource: self.resource.write().take()
        }
    }
}

/// Handle representing the shutdown process of a semaphore,
/// allowing for extraction of the underlying resource.
///
/// Returned from `Semaphore::shutdown`.
pub struct ShutdownHandle<T> {
    raw: Arc<RawSemaphore>,
    resource: Option<Arc<T>>
}

impl<T> ShutdownHandle<T> {
    /// Block until all access has been released to the semaphore,
    /// and extract the underlying resource.
    ///
    /// When `Semaphore::shutdown` has been called multiple times,
    /// only the first shutdown handle will return the resource.
    /// All others will return `None`.
    pub fn wait(self) -> Option<T> {
        self.raw.wait_until_inactive();
        self.resource.map(|arc| {
            let mut local_arc = arc;
            loop {
                match Arc::try_unwrap(local_arc) {
                    Ok(resource) => {
                        return resource;
                    },
                    Err(arc) => {
                        local_arc = arc;
                    }
                }
            }
        })
    }

    #[doc(hidden)]
    pub fn is_complete(&self) -> bool {
        !self.raw.is_active()
    }
}

/// RAII guard used to release access to the semaphore automatically when it falls out of scope.
///
/// Returned from `Semaphore::try_access`.
///
/// Guards can be cloned, in which case the original guard and all descendent guards need
/// to go out of scope for the single access to be released on the semaphore.
pub struct SemaphoreGuard<T> {
    raw: Arc<RawSemaphore>,
    counter: Arc<AtomicUsize>,
    resource: Arc<T>
}

impl<T> Clone for SemaphoreGuard<T> {
    #[inline]
    fn clone(&self) -> SemaphoreGuard<T> {
        self.counter.fetch_add(1, Ordering::SeqCst);
        SemaphoreGuard {
            raw: self.raw.clone(),
            counter: self.counter.clone(),
            resource: self.resource.clone()
        }
    }
}

impl<T> Drop for SemaphoreGuard<T> {
    fn drop(&mut self) {
        let previous_count = self.counter.fetch_sub(1, Ordering::SeqCst);
        if previous_count == 1 {
            self.raw.release();
        }
    }
}

impl<T: Sized> Deref for SemaphoreGuard<T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        self.resource.deref()
    }
}

#[cfg(test)]
mod tests {
    use super::{Semaphore, TryAccessError};

    #[test]
    fn succeeds_to_acquire_when_empty() {
        let sema = Semaphore::new(1, ());
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_full() {
        let sema = Semaphore::new(4, ());
        let guards = (0..4).map(|_| {
            sema.try_access().expect("guard acquisition failed")
        }).collect::<Vec<_>>();
        assert_eq!(sema.try_access().err().unwrap(),
            TryAccessError::NoCapacity);
        drop(guards);
    }

    #[test]
    fn dropping_guard_frees_capacity() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        drop(guard);
        assert!(sema.try_access().ok().is_some());
    }

    #[test]
    fn fails_to_acquire_when_shut_down() {
        let sema = Semaphore::new(4, ());
        sema.shutdown();
        assert_eq!(sema.try_access().err().unwrap(),
            TryAccessError::Shutdown);
    }

    #[test]
    fn shutdown_complete_when_empty() {
        let sema = Semaphore::new(1, ());
        let handle = sema.shutdown();
        assert_eq!(true, handle.is_complete());
    }

    #[test]
    fn shutdown_complete_when_guard_drops() {
        let sema = Semaphore::new(1, ());
        let guard = sema.try_access().expect("guard acquisition failed");
        let handle = sema.shutdown();
        assert_eq!(false, handle.is_complete());
        drop(guard);
        assert_eq!(true, handle.is_complete());
    }

    #[test]
    fn shutdown_complete_when_parent_and_child_guards_drop()  {
        let sema = Semaphore::new(1, ());
        let parent_guard = sema.try_access().expect("guard acquisition failed");
        let child_guard = parent_guard.clone();
        let handle = sema.shutdown();
        assert_eq!(false, handle.is_complete());
        drop(parent_guard);
        assert_eq!(false, handle.is_complete());
        drop(child_guard);
        assert_eq!(true, handle.is_complete());
    }
}
<|endoftext|>


<commit_before>// TODO:
//   - get completion actually working
//   - formatting

extern crate log;
extern crate simplelog;

use zydis;
use std::fs;
use std::env;
use std::collections;
use rayon::prelude::*;
use std::io::prelude::*;
use goblin::{Object};
use goblin::pe::{PE};
use log::{trace, debug, info, error};

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments")
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config {
            filename: filename
        })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info,
                                simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
}

fn align(i: usize, b: usize) -> usize {
    let rem = i % b;
    if rem == 0 {
        i
    } else {
        i + (b - rem)
    }
}

pub fn hexdump_ascii(b: u8) -> char {
    if b.is_ascii_graphic() || b == ' ' as u8 {
        b as char
    } else {
        '.'
    }
}

pub fn hexdump(buf: &[u8], offset: usize) -> String {
    // 01234567:  00 01 02 03 04 05 06 07  ...............
    // <prefix>   <hex col>                <ascii col>

    let padding = "  ";

    let padding_size = 2;
    let hex_col_size = 3;
    let ascii_col_size = 1;
    let prefix_size = 8 + 1;
    let newline_size = 1;
    let line_size = prefix_size +
                    padding_size +
                    16 * hex_col_size +
                    padding_size +
                    16 * ascii_col_size +
                    newline_size;
    let line_count = align(buf.len(), 0x10) / 0x10;

    let mut ret = String::with_capacity(line_count * line_size);

    let mut line = String::with_capacity(line_size);
    let mut remaining_count = buf.len();
    for line_index in 0..line_count {
        let line_elem_count = 0x10.min(remaining_count);
        let padding_elem_count = 0x10 - line_elem_count;

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        // ^^^^^^^^^
        line.push_str(format!("{:08x}:", offset + 0x10 * line_index).as_str());

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //          ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //            ^^^
        for elem in &buf[line_index..line_index+line_elem_count] {
            line.push_str(format!("{:02x} ", elem).as_str());
        }
        for _ in 0..padding_elem_count {
            line.push_str("   ");
        }

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                   ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                     ^
        for elem in &buf[line_index..line_index+line_elem_count] {
            line.push(hexdump_ascii(*elem))
        }
        for _ in 0..padding_elem_count {
            line.push(' ');
        }
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                                    ^
        line.push('\n');

        ret.push_str(line.as_str());
        line.truncate(0x0);
        remaining_count -= line_elem_count;
    }

    ret
}

fn foo(pe: &PE, buf: &[u8]) -> Result<(), Error> {
    info!("foo: {}", pe.name.unwrap_or("(unknown)"));

    // like:
    //
    //     exports:
    //       - Foo
    if pe.exports.len() > 0 {
        info!("exports:");
        for export in pe.exports.iter() {
            info!("  - {}", export.name.unwrap_or("(unknown)"));
        }
    }

    // like:
    //
    //     imports:
    //       - advapi32.dll
    //         - OpenProcessToken
    //         ...
    if pe.imports.len() > 0 {
        let mut dlls = pe.imports.iter()
                         .map(|import| {import.dll.to_lowercase()})
                         .collect::<collections::HashSet<String>>()
                         .iter()
                         .map(|e| {e.clone()})
                         .collect::<Vec<String>>();
        dlls.sort_unstable();

        info!("imports:");
        for dll in dlls.iter() {
            info!("  - {}", dll);

            let mut funcs: Vec<_> = pe.imports.iter()
                                          .filter(|import| { import.dll.to_lowercase() == **dll })
                                          .collect();
            funcs.sort_unstable_by(|a, b| { a.name.cmp(&b.name) });

            for func in funcs {
                info!("    - {}", func.name);
            }
        }
    }

    info!("bitness: {}", if pe.is_64 { "64" } else { "32"});
    info!("image base: 0x{:x}", pe.image_base);
    info!("entry rva: 0x{:x}", pe.entry);

    // like:
    //
    //     sections:
    //       - .text
    //         raw size:     0x18aa00
    //         virtual size: 0x18a9a8
    info!("sections:");
    for section in pe.sections.iter() {
        if section.real_name.is_some() {
            info!("  - {} ({})",
                  String::from_utf8_lossy(&section.name[..]),
                  section.real_name.as_ref().unwrap_or(&"(unknown)".to_string())
                  );
        } else {
            info!("  - {}", String::from_utf8_lossy(&section.name[..]));
        }

        info!("    raw size:     0x{:x}", section.size_of_raw_data);
        info!("    virtual size: 0x{:x}", section.virtual_size);

        // TODO: figure out if we will work with usize, or u64, or what, then assert usize is ok.
        // `usize::max_value()`
        let mut secbuf = vec![0; align(section.virtual_size as usize, 0x200)];

        {
            let secsize = section.size_of_raw_data as usize;
            let rawbuf = &mut secbuf[..secsize];
            let pstart = section.pointer_to_raw_data as usize;
            info!("pstart: 0x{:x}", pstart);
            info!("pend: 0x{:x}", pstart + secsize);
            rawbuf.copy_from_slice(&buf[pstart..pstart + secsize]);
        }

        info!("\n{}", hexdump(&secbuf[..0x1C], pe.image_base + section.virtual_address as usize));

        let decoder = zydis::Decoder::new(zydis::MachineMode::Long64, zydis::AddressWidth::_64).unwrap();
        //for ibuf in secbuf.windows(0x10) {
        //    let _ = decoder.decode(ibuf);
        //}
        let _: Vec<_> = secbuf.par_windows(0x10).map(|ibuf| {
            decoder.decode(ibuf)
        }).collect();
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", args.filename);
        let mut f = match fs::File::open(&args.filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", args.filename);
            return Err(Error::FileFormat);
        }
    }

    let obj = match Object::parse(&buf) {
        Ok(o) => o,
        Err(e) => {
            error!("failed to parse file: {} error: {:?}", args.filename, e);
            return Err(Error::FileFormat);
        }
    };

    match obj {
        Object::PE(pe) => {
            info!("found PE file");
            foo(&pe, &buf).expect("failed to foo")
        },
        Object::Elf(_) => {
            error!("found ELF file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Mach(_) => {
            error!("found Mach-O file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Archive(_) => {
            error!("found archive file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Unknown(_) => {
            error!("unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                   buf[0], buf[1],
                   hexdump_ascii(buf[0]),
                   hexdump_ascii(buf[1]));
            return Err(Error::NotImplemented);
        }
    }

    Ok(())
}

<commit_msg>lib: remove import/export parsing for now<commit_after>// TODO:
//   - get completion actually working
//   - formatting

extern crate log;
extern crate simplelog;

use zydis;
use std::fs;
use std::env;
use std::collections;
use rayon::prelude::*;
use std::io::prelude::*;
use goblin::{Object};
use goblin::pe::{PE};
use log::{trace, debug, info, error};

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments")
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config {
            filename: filename
        })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info,
                                simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
}

fn align(i: usize, b: usize) -> usize {
    let rem = i % b;
    if rem == 0 {
        i
    } else {
        i + (b - rem)
    }
}

pub fn hexdump_ascii(b: u8) -> char {
    if b.is_ascii_graphic() || b == ' ' as u8 {
        b as char
    } else {
        '.'
    }
}

pub fn hexdump(buf: &[u8], offset: usize) -> String {
    // 01234567:  00 01 02 03 04 05 06 07  ...............
    // <prefix>   <hex col>                <ascii col>

    let padding = "  ";

    let padding_size = 2;
    let hex_col_size = 3;
    let ascii_col_size = 1;
    let prefix_size = 8 + 1;
    let newline_size = 1;
    let line_size = prefix_size +
                    padding_size +
                    16 * hex_col_size +
                    padding_size +
                    16 * ascii_col_size +
                    newline_size;
    let line_count = align(buf.len(), 0x10) / 0x10;

    let mut ret = String::with_capacity(line_count * line_size);

    let mut line = String::with_capacity(line_size);
    let mut remaining_count = buf.len();
    for line_index in 0..line_count {
        let line_elem_count = 0x10.min(remaining_count);
        let padding_elem_count = 0x10 - line_elem_count;

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        // ^^^^^^^^^
        line.push_str(format!("{:08x}:", offset + 0x10 * line_index).as_str());

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //          ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //            ^^^
        for elem in &buf[line_index..line_index+line_elem_count] {
            line.push_str(format!("{:02x} ", elem).as_str());
        }
        for _ in 0..padding_elem_count {
            line.push_str("   ");
        }

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                   ^^
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                     ^
        for elem in &buf[line_index..line_index+line_elem_count] {
            line.push(hexdump_ascii(*elem))
        }
        for _ in 0..padding_elem_count {
            line.push(' ');
        }
        line.push_str(padding);

        // 01234567:  00 01 02 03 04 05 06 07  ...............
        //                                                    ^
        line.push('\n');

        ret.push_str(line.as_str());
        line.truncate(0x0);
        remaining_count -= line_elem_count;
    }

    ret
}

fn foo(pe: &PE, buf: &[u8]) -> Result<(), Error> {
    info!("foo: {}", pe.name.unwrap_or("(unknown)"));

    info!("bitness: {}", if pe.is_64 { "64" } else { "32"});
    info!("image base: 0x{:x}", pe.image_base);
    info!("entry rva: 0x{:x}", pe.entry);

    // like:
    //
    //     sections:
    //       - .text
    //         raw size:     0x18aa00
    //         virtual size: 0x18a9a8
    info!("sections:");
    for section in pe.sections.iter() {
        if section.real_name.is_some() {
            info!("  - {} ({})",
                  String::from_utf8_lossy(&section.name[..]),
                  section.real_name.as_ref().unwrap_or(&"(unknown)".to_string())
                  );
        } else {
            info!("  - {}", String::from_utf8_lossy(&section.name[..]));
        }

        info!("    raw size:     0x{:x}", section.size_of_raw_data);
        info!("    virtual size: 0x{:x}", section.virtual_size);

        // TODO: figure out if we will work with usize, or u64, or what, then assert usize is ok.
        // `usize::max_value()`
        let mut secbuf = vec![0; align(section.virtual_size as usize, 0x200)];

        {
            let secsize = section.size_of_raw_data as usize;
            let rawbuf = &mut secbuf[..secsize];
            let pstart = section.pointer_to_raw_data as usize;
            info!("pstart: 0x{:x}", pstart);
            info!("pend: 0x{:x}", pstart + secsize);
            rawbuf.copy_from_slice(&buf[pstart..pstart + secsize]);
        }

        info!("\n{}", hexdump(&secbuf[..0x1C], pe.image_base + section.virtual_address as usize));

        let decoder = zydis::Decoder::new(zydis::MachineMode::Long64, zydis::AddressWidth::_64).unwrap();
        //for ibuf in secbuf.windows(0x10) {
        //    let _ = decoder.decode(ibuf);
        //}
        let insns: Vec<_> = secbuf.par_windows(0x10).map(|ibuf| {
            decoder.decode(ibuf)
        }).collect();

        info!("l1: {}", insns.iter()
                             .filter(|insn| insn.is_ok())
                             .count());
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", args.filename);
        let mut f = match fs::File::open(&args.filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", args.filename);
            return Err(Error::FileFormat);
        }
    }

    let obj = match Object::parse(&buf) {
        Ok(o) => o,
        Err(e) => {
            error!("failed to parse file: {} error: {:?}", args.filename, e);
            return Err(Error::FileFormat);
        }
    };

    match obj {
        Object::PE(pe) => {
            info!("found PE file");
            foo(&pe, &buf).expect("failed to foo")
        },
        Object::Elf(_) => {
            error!("found ELF file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Mach(_) => {
            error!("found Mach-O file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Archive(_) => {
            error!("found archive file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Unknown(_) => {
            error!("unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                   buf[0], buf[1],
                   hexdump_ascii(buf[0]),
                   hexdump_ascii(buf[1]));
            return Err(Error::NotImplemented);
        }
    }

    Ok(())
}

<|endoftext|>