<commit_before>extern crate test;
use self::test::Bencher;

use super::Rope;
use std::iter;

#[bench]
fn rope_add_1000(b: &mut Bencher) {
    let mut rope = Rope::from(iter::repeat('a')
                                    .take(100_000)
                                    .collect::<String>());
    // rope.rebalance();
    b.iter(|| {
        let n = test::black_box(1000);
        // let mut rope = Rope::new();
        for i in 0..n {
            rope += i.to_string();
        }
    })

}

#[bench]
fn string_add_1000(b: &mut Bencher) {
    let mut string = iter::repeat('a').take(100_000).collect::<String>();
    b.iter(|| {
        let n = test::black_box(1000);
        // let mut string = String::new();
        for i in 0..n {
            string += &i.to_string();
        }
    })

}

#[bench]
fn rope_insert_1000(b: &mut Bencher) {
    let mut rope = Rope::from(iter::repeat('a')
                                    .take(100_000)
                                    .collect::<String>());
    // rope.rebalance();
    b.iter(|| {
        // let n = test::black_box(1000);
        // let mut rope = Rope::from("aaaa");
        for i in 0..1000 {
            rope.insert_str(2, &i.to_string());
        }
    })

}

#[bench]
fn string_insert_1000(b: &mut Bencher) {
    let mut string = iter::repeat('a').take(100_000).collect::<String>();
    b.iter(|| {
        // let n = test::black_box(1000);
        // let mut string = String::from("aaaa");
        for i in 0..1000 {
            string.insert_str(2, &i.to_string());
        }
    })

}

macro_rules! insert_benches {
    ( long: $lenl:expr, short: $lens:expr, $($name:ident: $frac:expr),* ) => {
        mod insert {
        mod rope {
            $(

                mod $name {
                    use ::Rope;
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    macro_rules! mk_bench {
                        ( $n:ident: $fun:ident, $l:expr, $ins:expr) => {
                            #[bench] fn $n(b: &mut Bencher) {
                                let mut rope = Rope::from(repeat('a').take($l)
                                                        .collect::<String>());
                                b.iter(|| { rope.$fun(
                                    ($l as f64 * $frac as f64) as usize, $ins)
                                })
                            }
                        }
                    }
                    mk_bench! { long: insert_str, $lenl, "bbbbbbb" }
                    mk_bench! { short: insert_str, $lens, "bb" }
                    mk_bench! { char_long: insert, $lenl, 'c' }
                    mk_bench! { char_short: insert, $lens, 'c' }
                    mk_bench! { rope_long: insert_rope, $lenl,
                        Rope::from(repeat('a').take($lenl)
                                    .collect::<String>()) }
                    mk_bench! { rope_short: insert_rope, $lens,
                        Rope::from(repeat('a').take($lens)
                                    .collect::<String>()) }
                }
            )*
        }
        mod string {
            $(
                mod $name {
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    macro_rules! mk_bench {
                        ( $n:ident: $fun:ident, $l:expr, $ins:expr) => {
                            #[bench] fn $n(b: &mut Bencher) {
                                let mut string = repeat('a').take($l)
                                                .collect::<String>();
                                b.iter(|| { string.$fun(
                                    ($l as f64 * $frac as f64) as usize, $ins)
                                })
                            }
                        }
                    }
                    mk_bench! { long: insert_str, $lenl, "bbbbbbb" }
                    mk_bench! { short: insert_str, $lens, "bb" }
                    mk_bench! { char_long: insert, $lenl, 'c' }
                    mk_bench! { char_short: insert, $lens, 'c'  }
                }
            )*
        }
    }}
}

macro_rules! split_benches {
    ( long: $lenl:expr, short: $lens:expr, $($name:ident: $frac:expr),* ) => {
        mod split {
            $(
                mod $name {
                    use ::Rope;
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    #[bench]
                    fn long(b: &mut Bencher) {
                        let rope = Rope::from(repeat('a').take($lenl)
                                                         .collect::<String>());
                        let split = || {
                            rope.clone()
                                .split(($lenl as f64 * $frac as f64) as usize) };
                        b.iter(split)
                    }
                    #[bench]
                    fn short(b: &mut Bencher) {
                        let rope = Rope::from(repeat('a').take($lens)
                                                         .collect::<String>());
                        let split = || {
                            rope.clone()
                                .split(($lens as f64 * $frac as f64) as usize) };
                        b.iter(split)
                    }
                }
            )*
        }
    }
}
#[cfg(all( test, feature = "unstable") )]
split_benches! {
    long: 100_000, short: 100,
        at_start: 0,
        at_quarter: 0.25,
        at_half: 0.5,
        at_3quarter: 0.75,
        at_end: 1
}
#[cfg(all( test, feature = "unstable") )]
insert_benches! {
    long: 100_000, short: 100,
        at_start: 0,
        at_quarter: 0.25,
        at_half: 0.5,
        at_3quarter: 0.75,
        at_end: 1
}
<commit_msg>test(rope benchmarks): benchmarks now build with persistent ropes<commit_after>extern crate test;
use self::test::Bencher;

use super::Rope;
use std::iter;

#[bench]
fn rope_add_1000(b: &mut Bencher) {
    let mut rope = Rope::from(iter::repeat('a')
                                    .take(100_000)
                                    .collect::<String>());
    // rope.rebalance();
    b.iter(|| {
        let n = test::black_box(1000);
        let mut r = rope.clone();
        for i in 0..n {
            r = r + i.to_string();
        }
    })

}

#[bench]
fn string_add_1000(b: &mut Bencher) {
    let mut string = iter::repeat('a').take(100_000).collect::<String>();
    b.iter(move || {
        let n = test::black_box(1000);
        let mut s = string.clone();
        for i in 0..n {
            s = s + &i.to_string();
        }
    })

}

#[bench]
fn rope_insert_1000(b: &mut Bencher) {
    let mut rope = Rope::from(iter::repeat('a')
                                    .take(100_000)
                                    .collect::<String>());
    // rope.rebalance();
    b.iter(move || {
        // let n = test::black_box(1000);
        // let mut rope = Rope::from("aaaa");
        for i in 0..1000 {
            rope.insert_str(2, &i.to_string());
        }
    })

}

#[bench]
fn string_insert_1000(b: &mut Bencher) {
    let mut string = iter::repeat('a').take(100_000).collect::<String>();
    b.iter(|| {
        // let n = test::black_box(1000);
        // let mut string = String::from("aaaa");
        for i in 0..1000 {
            string.insert_str(2, &i.to_string());
        }
    })

}

macro_rules! insert_benches {
    ( long: $lenl:expr, short: $lens:expr, $($name:ident: $frac:expr),* ) => {
        mod insert {
        mod rope {
            $(

                mod $name {
                    use ::Rope;
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    macro_rules! mk_bench {
                        ( $n:ident: $fun:ident, $l:expr, $ins:expr) => {
                            #[bench] fn $n(b: &mut Bencher) {
                                let mut rope = Rope::from(repeat('a').take($l)
                                                        .collect::<String>());
                                b.iter(|| { rope.$fun(
                                    ($l as f64 * $frac as f64) as usize, $ins)
                                })
                            }
                        }
                    }
                    mk_bench! { long: insert_str, $lenl, "bbbbbbb" }
                    mk_bench! { short: insert_str, $lens, "bb" }
                    mk_bench! { char_long: insert, $lenl, 'c' }
                    mk_bench! { char_short: insert, $lens, 'c' }
                    mk_bench! { rope_long: insert_rope, $lenl,
                        &Rope::from(repeat('a').take($lenl)
                                    .collect::<String>()) }
                    mk_bench! { rope_short: insert_rope, $lens,
                        &Rope::from(repeat('a').take($lens)
                                    .collect::<String>()) }
                }
            )*
        }
        mod string {
            $(
                mod $name {
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    macro_rules! mk_bench {
                        ( $n:ident: $fun:ident, $l:expr, $ins:expr) => {
                            #[bench] fn $n(b: &mut Bencher) {
                                let mut string = repeat('a').take($l)
                                                .collect::<String>();
                                b.iter(|| { string.$fun(
                                    ($l as f64 * $frac as f64) as usize, $ins)
                                })
                            }
                        }
                    }
                    mk_bench! { long: insert_str, $lenl, "bbbbbbb" }
                    mk_bench! { short: insert_str, $lens, "bb" }
                    mk_bench! { char_long: insert, $lenl, 'c' }
                    mk_bench! { char_short: insert, $lens, 'c'  }
                }
            )*
        }
    }}
}

macro_rules! split_benches {
    ( long: $lenl:expr, short: $lens:expr, $($name:ident: $frac:expr),* ) => {
        mod split {
            $(
                mod $name {
                    use ::Rope;
                    use ::bench::test::Bencher;
                    use std::iter::repeat;
                    #[bench]
                    fn long(b: &mut Bencher) {
                        let rope = Rope::from(repeat('a').take($lenl)
                                                         .collect::<String>());
                        let split = || {
                            rope.split(($lenl as f64 * $frac as f64) as usize) };
                        b.iter(split)
                    }
                    #[bench]
                    fn short(b: &mut Bencher) {
                        let rope = Rope::from(repeat('a').take($lens)
                                                         .collect::<String>());
                        let split = || {
                            rope.split(($lens as f64 * $frac as f64) as usize) };
                        b.iter(split)
                    }
                }
            )*
        }
    }
}
#[cfg(all( test, feature = "unstable") )]
split_benches! {
    long: 100_000, short: 100,
        at_start: 0,
        at_quarter: 0.25,
        at_half: 0.5,
        at_3quarter: 0.75,
        at_end: 1
}
#[cfg(all( test, feature = "unstable") )]
insert_benches! {
    long: 100_000, short: 100,
        at_start: 0,
        at_quarter: 0.25,
        at_half: 0.5,
        at_3quarter: 0.75,
        at_end: 1
}
<|endoftext|>


<commit_before>// Additional parameters for Android build of BoringSSL.
const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("arm", &[
        ("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("x86", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("x86_64", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
];

const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm64"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("arm", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("x86", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
    ("x86_64", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86_64"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
];

/// Returns the platform-specific output path for lib.
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
fn get_boringssl_platform_output_path(lib: &str) -> String {
    if cfg!(windows) {
        if cfg!(debug_assertions) {
            return format!("{}/Debug", lib);
        } else {
            return format!("{}/RelWithDebInfo", lib);
        }
    } else {
        return format!("{}", lib);
    };
}

/// Returns a new cmake::Config for building BoringSSL.
///
/// It will add platform-specific parameters if needed.
fn get_boringssl_cmake_config() -> cmake::Config {
    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();

    let mut boringssl_cmake = cmake::Config::new("deps/boringssl");

    // Add platform-specific parameters.
    return match os.as_ref() {
        "android" => {
            // We need ANDROID_NDK_HOME to be set properly.
            let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
                .expect("Please set ANDROID_NDK_HOME for Android build");
            for (android_arch, params) in CMAKE_PARAMS_ANDROID {
                if *android_arch == arch {
                    for (name, value) in *params {
                        let value = value
                            .replace("${ANDROID_NDK_HOME}", &android_ndk_home);
                        eprintln!("android arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            boringssl_cmake
        },

        "ios" => {
            for (ios_arch, params) in CMAKE_PARAMS_IOS {
                if *ios_arch == arch {
                    for (name, value) in *params {
                        eprintln!("ios arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            // bitcode on
            boringssl_cmake.define("CMAKE_ASM_FLAGS", "-fembed-bitcode");
            boringssl_cmake.cflag("-fembed-bitcode");

            boringssl_cmake
        },

        _ => boringssl_cmake,
    };
}

fn write_pkg_config() {
    use std::io::prelude::*;

    let profile = std::env::var("PROFILE").unwrap();
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = format!("{}/target/{}", manifest_dir, profile);

    let out_path = std::path::Path::new(&target_dir).join("quiche.pc");
    let mut out_file = std::fs::File::create(&out_path).unwrap();

    let include_dir = format!("{}/include", manifest_dir);
    let version = std::env::var("CARGO_PKG_VERSION").unwrap();

    let output = format!(
        "# quiche

includedir={}
libdir={}

Name: quiche
Description: quiche library
URL: https://github.com/cloudflare/quiche
Version: {}
Libs: -Wl,-rpath,${{libdir}} -L${{libdir}} -lquiche
Cflags: -I${{includedir}}
",
        include_dir, target_dir, version
    );

    out_file.write_all(output.as_bytes()).unwrap();
}

fn main() {
    if cfg!(feature = "boringssl-vendored") {
        let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
            let mut cfg = get_boringssl_cmake_config();

            if cfg!(feature = "fuzzing") {
                cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
                    .cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
            }

            cfg.build_target("bssl").build().display().to_string()
        });

        let crypto_path = get_boringssl_platform_output_path("crypto");
        let crypto_dir = format!("{}/build/{}", bssl_dir, crypto_path);
        println!("cargo:rustc-link-search=native={}", crypto_dir);
        println!("cargo:rustc-link-lib=static=crypto");

        let ssl_path = get_boringssl_platform_output_path("ssl");
        let ssl_dir = format!("{}/build/{}", bssl_dir, ssl_path);
        println!("cargo:rustc-link-search=native={}", ssl_dir);
        println!("cargo:rustc-link-lib=static=ssl");
    }

    if cfg!(feature = "pkg-config-meta") {
        write_pkg_config();
    }
}
<commit_msg>build: fix cdylib build with --no-default-features on macOS<commit_after>// Additional parameters for Android build of BoringSSL.
const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("arm", &[
        ("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("x86", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
    ("x86_64", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
        ("ANDROID_STL", "c++_shared"),
    ]),
];

const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm64"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("arm", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("x86", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
    ("x86_64", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86_64"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
];

/// Returns the platform-specific output path for lib.
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
fn get_boringssl_platform_output_path(lib: &str) -> String {
    if cfg!(windows) {
        if cfg!(debug_assertions) {
            return format!("{}/Debug", lib);
        } else {
            return format!("{}/RelWithDebInfo", lib);
        }
    } else {
        return format!("{}", lib);
    };
}

/// Returns a new cmake::Config for building BoringSSL.
///
/// It will add platform-specific parameters if needed.
fn get_boringssl_cmake_config() -> cmake::Config {
    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();

    let mut boringssl_cmake = cmake::Config::new("deps/boringssl");

    // Add platform-specific parameters.
    return match os.as_ref() {
        "android" => {
            // We need ANDROID_NDK_HOME to be set properly.
            let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
                .expect("Please set ANDROID_NDK_HOME for Android build");
            for (android_arch, params) in CMAKE_PARAMS_ANDROID {
                if *android_arch == arch {
                    for (name, value) in *params {
                        let value = value
                            .replace("${ANDROID_NDK_HOME}", &android_ndk_home);
                        eprintln!("android arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            boringssl_cmake
        },

        "ios" => {
            for (ios_arch, params) in CMAKE_PARAMS_IOS {
                if *ios_arch == arch {
                    for (name, value) in *params {
                        eprintln!("ios arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            // bitcode on
            boringssl_cmake.define("CMAKE_ASM_FLAGS", "-fembed-bitcode");
            boringssl_cmake.cflag("-fembed-bitcode");

            boringssl_cmake
        },

        _ => boringssl_cmake,
    };
}

fn write_pkg_config() {
    use std::io::prelude::*;

    let profile = std::env::var("PROFILE").unwrap();
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = format!("{}/target/{}", manifest_dir, profile);

    let out_path = std::path::Path::new(&target_dir).join("quiche.pc");
    let mut out_file = std::fs::File::create(&out_path).unwrap();

    let include_dir = format!("{}/include", manifest_dir);
    let version = std::env::var("CARGO_PKG_VERSION").unwrap();

    let output = format!(
        "# quiche

includedir={}
libdir={}

Name: quiche
Description: quiche library
URL: https://github.com/cloudflare/quiche
Version: {}
Libs: -Wl,-rpath,${{libdir}} -L${{libdir}} -lquiche
Cflags: -I${{includedir}}
",
        include_dir, target_dir, version
    );

    out_file.write_all(output.as_bytes()).unwrap();
}

fn main() {
    if cfg!(feature = "boringssl-vendored") {
        let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
            let mut cfg = get_boringssl_cmake_config();

            if cfg!(feature = "fuzzing") {
                cfg.cxxflag("-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE")
                    .cxxflag("-DBORINGSSL_UNSAFE_FUZZER_MODE");
            }

            cfg.build_target("bssl").build().display().to_string()
        });

        let crypto_path = get_boringssl_platform_output_path("crypto");
        let crypto_dir = format!("{}/build/{}", bssl_dir, crypto_path);
        println!("cargo:rustc-link-search=native={}", crypto_dir);
        println!("cargo:rustc-link-lib=static=crypto");

        let ssl_path = get_boringssl_platform_output_path("ssl");
        let ssl_dir = format!("{}/build/{}", bssl_dir, ssl_path);
        println!("cargo:rustc-link-search=native={}", ssl_dir);
        println!("cargo:rustc-link-lib=static=ssl");
    }

    // MacOS: Allow cdylib to link with undefined symbols
    if cfg!(target_os = "macos") {
        println!("cargo:rustc-cdylib-link-arg=-Wl,-undefined,dynamic_lookup");
    }

    if cfg!(feature = "pkg-config-meta") {
        write_pkg_config();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017, 2018 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use strum::IntoEnumIterator;
use arrayvec::ArrayVec;
use rand::Rng;

use std::ops::Deref;

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Color
{
    #[strum(serialize="?")]
    Unknown,
    #[strum(serialize="♠")]
    Spades,
    #[strum(serialize="♥")]
    Hearts,
    #[strum(serialize="♦")]
    Diamonds,
    #[strum(serialize="♣")]
    Clubs
}

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Rank
{
    #[strum(serialize="?")]
    Unknown,
    A,
    #[strum(serialize="2")]
    Two,
    #[strum(serialize="3")]
    Three,
    #[strum(serialize="4")]
    Four,
    #[strum(serialize="5")]
    Five,
    #[strum(serialize="6")]
    Six,
    #[strum(serialize="7")]
    Seven,
    #[strum(serialize="8")]
    Eight,
    #[strum(serialize="9")]
    Nine,
    #[strum(serialize="10")]
    Ten,
    J,
    Q,
    K
}

pub struct Card
{
    pub color:     Color,
    pub rank:      Rank,
    pub id:        i8,
    pub facing_up: bool
}

// TODO: Change to ArrayVec<[Card; 52]> after PR for that size has been merged.
type Deck = ArrayVec<[Card; 56]>;

pub struct ShuffledDeck(Deck);

NewtypeFrom! { () pub struct ShuffledDeck(Deck); }

impl ShuffledDeck
{
    pub fn new () -> ShuffledDeck
    {
        /*
         * The cards in the shuffled deck appear in order of their IDs,
         * such that the card with ID n is at array position n.
         */

        let mut deck = Deck::new();

        let mut card_ids: Vec<i8> = (0..52).collect();
        rand::thread_rng().shuffle(&mut card_ids);

        let mut card_ids_iter = card_ids.iter_mut();

        for color in Color::iter().skip(1)
        {
            for rank in Rank::iter().skip(1)
            {
                deck.push(Card
                {
                    color:     color,
                    rank:      rank,
                    id:        *(card_ids_iter.next().unwrap()),
                    facing_up: false
                });
            }
        }

        deck.sort_unstable_by_key(|k| k.id);

        ShuffledDeck::from(deck)
    }

    pub fn push (&mut self, element: <[Card; 56] as arrayvec::Array>::Item)
    {
        Deck::push(&mut self.0, element)
    }
}

impl Deref for ShuffledDeck
{
    type Target = [<[Card; 56] as arrayvec::Array>::Item];

    #[inline]
    fn deref (&self) -> &[<[Card; 56] as arrayvec::Array>::Item]
    {
        Deck::deref(&self.0)
    }
}
<commit_msg>Use an alias so we don't have to repeat the capacity of the array all over the place.<commit_after>/*
 * Copyright (c) 2017, 2018 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use strum::IntoEnumIterator;
use arrayvec::ArrayVec;
use rand::Rng;

use std::ops::Deref;

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Color
{
    #[strum(serialize="?")]
    Unknown,
    #[strum(serialize="♠")]
    Spades,
    #[strum(serialize="♥")]
    Hearts,
    #[strum(serialize="♦")]
    Diamonds,
    #[strum(serialize="♣")]
    Clubs
}

#[derive(EnumIter, Display, Copy, Clone)]
pub enum Rank
{
    #[strum(serialize="?")]
    Unknown,
    A,
    #[strum(serialize="2")]
    Two,
    #[strum(serialize="3")]
    Three,
    #[strum(serialize="4")]
    Four,
    #[strum(serialize="5")]
    Five,
    #[strum(serialize="6")]
    Six,
    #[strum(serialize="7")]
    Seven,
    #[strum(serialize="8")]
    Eight,
    #[strum(serialize="9")]
    Nine,
    #[strum(serialize="10")]
    Ten,
    J,
    Q,
    K
}

pub struct Card
{
    pub color:     Color,
    pub rank:      Rank,
    pub id:        i8,
    pub facing_up: bool
}

// TODO: Change to ArrayVec<[Card; 52]> after PR for that size has been merged.
type DeckArray = [Card; 56];
type Deck = ArrayVec<DeckArray>;

pub struct ShuffledDeck(Deck);

NewtypeFrom! { () pub struct ShuffledDeck(Deck); }

impl ShuffledDeck
{
    pub fn new () -> ShuffledDeck
    {
        /*
         * The cards in the shuffled deck appear in order of their IDs,
         * such that the card with ID n is at array position n.
         */

        let mut deck = Deck::new();

        let mut card_ids: Vec<i8> = (0..52).collect();
        rand::thread_rng().shuffle(&mut card_ids);

        let mut card_ids_iter = card_ids.iter_mut();

        for color in Color::iter().skip(1)
        {
            for rank in Rank::iter().skip(1)
            {
                deck.push(Card
                {
                    color:     color,
                    rank:      rank,
                    id:        *(card_ids_iter.next().unwrap()),
                    facing_up: false
                });
            }
        }

        deck.sort_unstable_by_key(|k| k.id);

        ShuffledDeck::from(deck)
    }

    pub fn push (&mut self, element: <DeckArray as arrayvec::Array>::Item)
    {
        Deck::push(&mut self.0, element)
    }
}

impl Deref for ShuffledDeck
{
    type Target = [<DeckArray as arrayvec::Array>::Item];

    #[inline]
    fn deref (&self) -> &[<DeckArray as arrayvec::Array>::Item]
    {
        Deck::deref(&self.0)
    }
}
<|endoftext|>


<commit_before>use ansi_term::Colour::Green;

#[derive(Debug)]
pub struct Machine {
    id: String,
    name: String,
    provider: String,
    state: String,
    path: String,
}

impl Machine {
    // Use of the Into Trait https://doc.rust-lang.org/nightly/core/convert/trait.Into.html
    // Let the caller to pass either a String or &str type
    // pub fn from_output_line<S: Into<String>>(line: S) -> Machine {
    pub fn from_output_line<S>(line: S) -> Machine
        where S: Into<String>
    {
        let line = line.into();
        let words: Vec<&str> = line.split_whitespace().collect();

        Machine {
            id: words[0].to_string(),
            name: words[1].to_string(),
            provider: words[2].to_string(),
            state: words[3].to_string(),
            path: words[4].to_string(),
        }
    }

    pub fn get_path(&self) -> &str {
        self.path.as_str()
    }

    pub fn get_vagrant_file_path(&self) -> String {
        let mut file = self.path.clone();
        file.push_str("/Vagrantfile");

        file
    }

    pub fn to_output(&self) {
        let output = format!("{0: ^10} | {1: ^10} | {2: ^10} | {3: ^10} | {4: ^10}",
                             self.id.as_str(),
                             self.name.as_str(),
                             self.provider.as_str(),
                             self.state.as_str(),
                             self.path.as_str());
        println!("{}", Green.paint(output));
    }

    pub fn is_running(&self) -> bool {
        self.state == "running"
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn it_retrieves_the_vm_path() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert_eq!(m.get_path(), "/path/to/vm");
    }

    #[test]
    fn it_retrieves_the_vagrant_file_path() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert_eq!(m.get_vagrant_file_path(), "/path/to/vm/Vagrantfile");
    }

    #[test]
    fn it_knows_when_the_vm_is_not_running() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert!(!m.is_running());
    }

    #[test]
    fn it_knows_when_the_vm_is_running() {
        let m = Machine::from_output_line("00057e0 default virtualbox running /path/to/vm".to_string());
        assert!(m.is_running());
    }
}
<commit_msg>Remove dead code<commit_after>use ansi_term::Colour::Green;

#[derive(Debug)]
pub struct Machine {
    id: String,
    name: String,
    provider: String,
    state: String,
    path: String,
}

impl Machine {
    // Use of the Into Trait https://doc.rust-lang.org/nightly/core/convert/trait.Into.html
    // Let the caller to pass either a String or &str type
    // pub fn from_output_line<S: Into<String>>(line: S) -> Machine {
    pub fn from_output_line<S>(line: S) -> Machine
        where S: Into<String>
    {
        let line = line.into();
        let words: Vec<&str> = line.split_whitespace().collect();

        Machine {
            id: words[0].to_string(),
            name: words[1].to_string(),
            provider: words[2].to_string(),
            state: words[3].to_string(),
            path: words[4].to_string(),
        }
    }

    pub fn get_path(&self) -> &str {
        self.path.as_str()
    }

    pub fn get_vagrant_file_path(&self) -> String {
        let mut file = self.path.clone();
        file.push_str("/Vagrantfile");
        file
    }

    pub fn to_output(&self) {
        let output = format!("{0: ^10} | {1: ^10} | {2: ^10} | {3: ^10} | {4: ^10}",
                             self.id.as_str(),
                             self.name.as_str(),
                             self.provider.as_str(),
                             self.state.as_str(),
                             self.path.as_str());
        println!("{}", Green.paint(output));
    }

    pub fn is_running(&self) -> bool {
        self.state == "running"
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn it_retrieves_the_vm_path() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert_eq!(m.get_path(), "/path/to/vm");
    }

    #[test]
    fn it_retrieves_the_vagrant_file_path() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert_eq!(m.get_vagrant_file_path(), "/path/to/vm/Vagrantfile");
    }

    #[test]
    fn it_knows_when_the_vm_is_not_running() {
        let m = Machine::from_output_line("00057e0 default virtualbox aborted /path/to/vm");
        assert!(!m.is_running());
    }

    #[test]
    fn it_knows_when_the_vm_is_running() {
        let m = Machine::from_output_line("00057e0 default virtualbox running /path/to/vm");
        assert!(m.is_running());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};

use byteorder::{BigEndian, ReadBytesExt};

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Indentifier: 'Pict'.
    /// Indicates the resource is an image.
    Pict,

    /// Indentifier: 'Snd '.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: 'Data'.
    /// Indicates the resource is some data.
    Data,

    /// Indentifier: 'Exec'.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    pub usage: Usage,
    pub num: u32,
    start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    pub entries: HashMap<usize, IndexEntry>,
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    pub id: String,
    len: u32,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: 'RIdx'.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the form.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: 'IFmd'.
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: 'Fspec'.
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: 'GLUL'.
    /// Contains Glulx executable.
    /// This is a executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: 'PNG '.
    /// Contains a PNG image.
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: 'JPEG'.
    /// Contains a JPEG image.
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}

/// Access point for lazy loading blorb contents. This struct contains
/// the methods to load resources from the provided blorb. This does not
/// cache the results.
pub struct Blorb<R: Read + Seek> {
    /// The length of the IFRS chunk
    pub len: u32,
    index: ResourceIndex,
    file: R,
}

impl<R: Read + Seek> Blorb<R> {

    /// Creates a new Blorb from a file. The code goes through the
    /// given game file, validates the file type, and extracts the
    /// basic game objects for the blorb.
    pub fn from_file(file: R) -> Result<Blorb<R>, Error> {
        let mut file = file;

        let form = try!(Blorb::load_chunk_data(&mut file));
        assert_eq!(&form.id, "FORM");

        // Check that the form type is IFRS
        let id = try!(Blorb::load_4bw(&mut file));
        assert_eq!(&id, "IFRS");

        let index = if let Chunk::ResourceIndex{index} =
                try!(Blorb::load_chunk(&mut file)) {
            index
        } else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not locate index"
            ));
        };

        Ok(Blorb{
            len: form.len,
            index: index,
            file: file,
        })
    }

    /// loads a resource using the given index entry.
    pub fn load_resource(&mut self, num: usize) -> Result<Chunk, Error> {
        let entry = match self.index.entries.get(&num) {
            Some(entry) => entry,
            None => {
                return Err(Error::new(
                    ErrorKind::NotFound,
                    "resource not found"
                ))
            },
        };
        try!(self.file.seek(SeekFrom::Start(entry.start as u64)));

        Blorb::load_chunk(&mut self.file)
    }

    /// Load a `Chunk` from the file.
    fn load_chunk(file: &mut R) -> Result<Chunk, Error> {
        let meta = try!(Blorb::load_chunk_data(file));

        match meta.id.as_ref() {
            "RIdx" => {
                let num = try!(file.read_u32::<BigEndian>());
                let mut entries = HashMap::with_capacity(num as usize);
                for _ in 0..num {
                    let entry = try!(Blorb::load_index_entry(file));
                    entries.insert(entry.num as usize, entry);
                }

                Ok(Chunk::ResourceIndex{index: ResourceIndex{entries:entries}})
            },
            "GLUL" => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Glulx{code: data})
            },
            _ => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Unknown{meta: meta, data: data})
            },
        }
    }

    /// Load an `IndexEntry` from the file.
    fn load_index_entry(file: &mut R) -> Result<IndexEntry, Error> {
        let usage = try!(Blorb::load_4bw(file));
        let num = try!(file.read_u32::<BigEndian>());
        let start = try!(file.read_u32::<BigEndian>());

        let usage = match usage.as_ref() {
            "Pict" => Usage::Pict,
            "Snd " => Usage::Snd,
            "Data" => Usage::Data,
            "Exec" => Usage::Exec,
            _ => return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not identify index entry usage"
            )),
        };

        Ok(IndexEntry{usage: usage, num: num, start: start})
    }

    /// Read a chunk and return the metadata in the form of a
    /// `ChunkData`.
    fn load_chunk_data(file: &mut R) -> Result<ChunkData, Error> {
        let id = try!(Blorb::load_4bw(file));
        let len = try!(file.read_u32::<BigEndian>());
        Ok(ChunkData{id: id, len: len})
    }

    /// Load a 4 byte ASCII word from the file
    fn load_4bw(file: &mut R) -> Result<String, Error> {
        let mut id = String::with_capacity(0x4);
        try!(file.take(4).read_to_string(&mut id));
        Ok(id)
    }
}
<commit_msg>fixed spelling mistakes prior to release 0.1.0<commit_after>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};

use byteorder::{BigEndian, ReadBytesExt};

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Identifier: 'Pict'.
    /// Indicates the resource is an image.
    Pict,

    /// Identifier: 'Snd '.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: 'Data'.
    /// Indicates the resource is some data.
    Data,

    /// Identifier: 'Exec'.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    pub usage: Usage,
    pub num: u32,
    start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    pub entries: HashMap<usize, IndexEntry>,
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    pub id: String,
    len: u32,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: 'RIdx'.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the form.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: 'IFmd'.
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: 'Fspec'.
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: 'GLUL'.
    /// Contains Glulx executable.
    /// This is a executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: 'PNG '.
    /// Contains a PNG image.
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: 'JPEG'.
    /// Contains a JPEG image.
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}

/// Access point for lazy loading blorb contents. This struct contains
/// the methods to load resources from the provided blorb. This does not
/// cache the results.
pub struct Blorb<R: Read + Seek> {
    /// The length of the IFRS chunk
    pub len: u32,
    index: ResourceIndex,
    file: R,
}

impl<R: Read + Seek> Blorb<R> {

    /// Creates a new Blorb from a file. The code goes through the
    /// given game file, validates the file type, and extracts the
    /// basic game objects for the blorb.
    pub fn from_file(file: R) -> Result<Blorb<R>, Error> {
        let mut file = file;

        let form = try!(Blorb::load_chunk_data(&mut file));
        assert_eq!(&form.id, "FORM");

        // Check that the form type is IFRS
        let id = try!(Blorb::load_4bw(&mut file));
        assert_eq!(&id, "IFRS");

        let index = if let Chunk::ResourceIndex{index} =
                try!(Blorb::load_chunk(&mut file)) {
            index
        } else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not locate index"
            ));
        };

        Ok(Blorb{
            len: form.len,
            index: index,
            file: file,
        })
    }

    /// loads a resource using the given index entry.
    pub fn load_resource(&mut self, num: usize) -> Result<Chunk, Error> {
        let entry = match self.index.entries.get(&num) {
            Some(entry) => entry,
            None => {
                return Err(Error::new(
                    ErrorKind::NotFound,
                    "resource not found"
                ))
            },
        };
        try!(self.file.seek(SeekFrom::Start(entry.start as u64)));

        Blorb::load_chunk(&mut self.file)
    }

    /// Load a `Chunk` from the file.
    fn load_chunk(file: &mut R) -> Result<Chunk, Error> {
        let meta = try!(Blorb::load_chunk_data(file));

        match meta.id.as_ref() {
            "RIdx" => {
                let num = try!(file.read_u32::<BigEndian>());
                let mut entries = HashMap::with_capacity(num as usize);
                for _ in 0..num {
                    let entry = try!(Blorb::load_index_entry(file));
                    entries.insert(entry.num as usize, entry);
                }

                Ok(Chunk::ResourceIndex{index: ResourceIndex{entries:entries}})
            },
            "GLUL" => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Glulx{code: data})
            },
            _ => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Unknown{meta: meta, data: data})
            },
        }
    }

    /// Load an `IndexEntry` from the file.
    fn load_index_entry(file: &mut R) -> Result<IndexEntry, Error> {
        let usage = try!(Blorb::load_4bw(file));
        let num = try!(file.read_u32::<BigEndian>());
        let start = try!(file.read_u32::<BigEndian>());

        let usage = match usage.as_ref() {
            "Pict" => Usage::Pict,
            "Snd " => Usage::Snd,
            "Data" => Usage::Data,
            "Exec" => Usage::Exec,
            _ => return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not identify index entry usage"
            )),
        };

        Ok(IndexEntry{usage: usage, num: num, start: start})
    }

    /// Read a chunk and return the metadata in the form of a
    /// `ChunkData`.
    fn load_chunk_data(file: &mut R) -> Result<ChunkData, Error> {
        let id = try!(Blorb::load_4bw(file));
        let len = try!(file.read_u32::<BigEndian>());
        Ok(ChunkData{id: id, len: len})
    }

    /// Load a 4 byte ASCII word from the file
    fn load_4bw(file: &mut R) -> Result<String, Error> {
        let mut id = String::with_capacity(0x4);
        try!(file.take(4).read_to_string(&mut id));
        Ok(id)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers.
// Copyright 2015 Guillaume Gomez
//
// 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.

//! Library to interface with chunks of memory allocated in C.
//!
//! It is often desirable to safely interface with memory allocated from C,
//! encapsulating the unsafety into allocation and destruction time.  Indeed,
//! allocating memory externally is currently the only way to give Rust shared
//! mut state with C programs that keep their own references; vectors are
//! unsuitable because they could be reallocated or moved at any time, and
//! importing C memory into a vector takes a one-time snapshot of the memory.
//!
//! This module simplifies the usage of such external blocks of memory.  Memory
//! is encapsulated into an opaque object after creation; the lifecycle of the
//! memory can be optionally managed by Rust, if an appropriate destructor
//! closure is provided.  Safety is ensured by bounds-checking accesses, which
//! are marshalled through get and set functions.
//!
//! There are three unsafe functions: the two constructors, and the
//! unwrapping method. The constructors are unsafe for the
//! obvious reason (they act on a pointer that cannot be checked inside the
//! method), but `into_inner()` is somewhat more subtle in its unsafety.
//! It returns the contained pointer, but at the same time destroys the CVec
//! without running its destructor. This can be used to pass memory back to
//! C, but care must be taken that the ownership of underlying resources are
//! handled correctly, i.e. that allocated memory is eventually freed
//! if necessary.

#![feature(unsafe_destructor, core, std_misc, unique)]

use std::mem;
use std::ptr;
use std::raw;
use std::ptr::Unique;
use std::thunk::Invoke;
use std::ops::{Index, IndexMut};

/// The type representing a foreign chunk of memory
pub struct CVec<T> {
    base: Unique<T>,
    len: usize,
    dtor: Option<Box<Invoke<*mut T> + 'static>>
}

#[unsafe_destructor]
impl<T> Drop for CVec<T> {
    fn drop(&mut self) {
        match self.dtor.take() {
            None => (),
            Some(f) => f.invoke(*self.base),
        }
    }
}

impl<T> CVec<T> {
    /// Create a `CVec` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A unique pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: Unique<T>, len: usize) -> CVec<T> {
        assert!(*base != ptr::null_mut());
        CVec {
            base: base,
            len: len,
            dtor: None,
        }
    }

    /// Create a `CVec` from a foreign buffer, with a given length,
    /// and a function to run upon destruction.
    ///
    /// Panics if the given pointer is null.
    ///
    /// # Arguments
    ///
    /// * base - A unique pointer to a buffer
    /// * len - The number of elements in the buffer
    /// * dtor - A fn to run when the value is destructed, useful
    ///          for freeing the buffer, etc. `base` will be passed
    ///          to it as an argument.
    pub unsafe fn new_with_dtor<F>(base: Unique<T>,
                                   len: usize,
                                   dtor: F)
                                   -> CVec<T>
        where F : FnOnce(*mut T) + 'static
    {
        assert!(*base != ptr::null_mut());
        let dtor = Box::new(dtor);
        CVec {
            base: base,
            len: len,
            dtor: Some(dtor)
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: *self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Unwrap the pointer without running the destructor
    ///
    /// This method retrieves the underlying pointer, and in the process
    /// destroys the CVec but without running the destructor. A use case
    /// would be transferring ownership of the buffer to a C function, as
    /// in this case you would not want to run the destructor.
    ///
    /// Note that if you want to access the underlying pointer without
    /// cancelling the destructor, you can simply call `transmute` on the return
    /// value of `get(0)`.
    pub unsafe fn into_inner(mut self) -> *mut T {
        self.dtor = None;
        *self.base
    }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Convert to CSlice
    pub fn as_cslice(&self) -> CSlice<T> {
        CSlice {
            base: *self.base,
            len: self.len
        }
    }
}

impl<T> AsSlice<T> for CVec<T> {
    /// View the stored data as a slice.
    fn as_slice<'a>(&'a self) -> &'a [T] {
        unsafe {
            mem::transmute(raw::Slice { data: *self.base as *const T, len: self.len })
        }
    }
}

/// The type representing an 'unsafe' foreign chunk of memory
pub struct CSlice<T> {
    base: *mut T,
    len: usize
}

impl<T> CSlice<T> {
    /// Create a `CSlice` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A raw pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: *mut T, len: usize) -> CSlice<T> {
        assert!(base != ptr::null_mut());
        CSlice {
            base: base,
            len: len
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> Index<usize> for CSlice<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        assert!(*_index < self.len);
        unsafe { &*self.base.offset(*_index as isize) }
    }
}

impl<T> IndexMut<usize> for CSlice<T> {
    fn index_mut<'a>(&'a mut self, _index: &usize) -> &'a mut T {
        assert!(*_index < self.len);
        unsafe { &mut *self.base.offset(*_index as isize) }
    }
}

#[cfg(test)]
mod tests {
    extern crate alloc;
    extern crate libc;

    use super::{CVec, CSlice};
    use std::ptr::{self, Unique};

    // allocation of CVec
    fn v_malloc(n: usize) -> CVec<u8> {
        unsafe {
            let mem: Unique<u8> = Unique::new(
                libc::malloc(n as libc::size_t) as *mut _);
            if (*mem).is_null() { alloc::oom() }

            CVec::new_with_dtor(mem, n,
                                |mem| { libc::free((mem) as *mut _); })
        }
    }

    // allocation of CSlice
    fn s_malloc(n: usize) -> CSlice<u8> {
        unsafe {
            let mem: *mut u8 = libc::malloc(n as libc::size_t) as *mut _;
            if mem.is_null() { alloc::oom() }

            CSlice::new(mem, n)
        }
    }

    #[test]
    fn vec_test_basic() {
        let mut cv = v_malloc(16);

        *cv.get_mut(3).unwrap() = 8;
        *cv.get_mut(4).unwrap() = 9;
        assert_eq!(*cv.get(3).unwrap(), 8);
        assert_eq!(*cv.get(4).unwrap(), 9);
        assert_eq!(cv.len(), 16);
    }

    #[test]
    fn slice_test_basic() {
        let mut cs = s_malloc(16);

        cs[3] = 8;
        cs[4] = 9;
        assert_eq!(cs[3], 8);
        assert_eq!(cs[4], 9);
        assert_eq!(cs.len(), 16);
    }

    #[test]
    #[should_fail]
    fn vec_test_panic_at_null() {
        unsafe {
            CVec::new(Unique::new(ptr::null_mut::<u8>()), 9);
        }
    }

    #[test]
    #[should_fail]
    fn slice_test_panic_at_null() {
        unsafe {
            CSlice::new(ptr::null_mut::<u8>(), 9);
        }
    }

    #[test]
    fn vec_test_overrun_get() {
        let cv = v_malloc(16);

        assert!(cv.get(17).is_none());
    }

    #[test]
    #[should_fail]
    fn slice_test_overrun_get() {
        let cs = s_malloc(16);

        assert!(cs[17] == 18);
    }

    #[test]
    fn vec_test_overrun_set() {
        let mut cv = v_malloc(16);

        assert!(cv.get_mut(17).is_none());
    }

    #[test]
    fn vec_test_unwrap() {
        unsafe {
            let cv = CVec::new_with_dtor(Unique::new(1 as *mut isize),
                                         0,
                                         |_| panic!("Don't run this destructor!"));
            let p = cv.into_inner();
            assert_eq!(p, 1 as *mut isize);
        }
    }

    #[test]
    fn vec_to_slice_test() {
        unsafe {
            let mut cv = v_malloc(2);

            *cv.get_mut(0).unwrap() = 10;
            *cv.get_mut(1).unwrap() = 12;
            let cs = cv.as_cslice();

            assert_eq!(cs[0], 10);
            assert_eq!(cs[1], 12);
        }
    }

    #[test]
    fn slice_to_vec_test() {
        let cv = v_malloc(2);
        let mut cs = cv.as_cslice();

        cs[0] = 13;
        cs[1] = 26;
        assert_eq!(*cv.get(0).unwrap(), 13);
        assert_eq!(*cv.get(1).unwrap(), 26);
    }
}
<commit_msg>Add back as_slice method for CSlice<commit_after>// Copyright 2012 The Rust Project Developers.
// Copyright 2015 Guillaume Gomez
//
// 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.

//! Library to interface with chunks of memory allocated in C.
//!
//! It is often desirable to safely interface with memory allocated from C,
//! encapsulating the unsafety into allocation and destruction time.  Indeed,
//! allocating memory externally is currently the only way to give Rust shared
//! mut state with C programs that keep their own references; vectors are
//! unsuitable because they could be reallocated or moved at any time, and
//! importing C memory into a vector takes a one-time snapshot of the memory.
//!
//! This module simplifies the usage of such external blocks of memory.  Memory
//! is encapsulated into an opaque object after creation; the lifecycle of the
//! memory can be optionally managed by Rust, if an appropriate destructor
//! closure is provided.  Safety is ensured by bounds-checking accesses, which
//! are marshalled through get and set functions.
//!
//! There are three unsafe functions: the two constructors, and the
//! unwrapping method. The constructors are unsafe for the
//! obvious reason (they act on a pointer that cannot be checked inside the
//! method), but `into_inner()` is somewhat more subtle in its unsafety.
//! It returns the contained pointer, but at the same time destroys the CVec
//! without running its destructor. This can be used to pass memory back to
//! C, but care must be taken that the ownership of underlying resources are
//! handled correctly, i.e. that allocated memory is eventually freed
//! if necessary.

#![feature(unsafe_destructor, core, std_misc, unique)]

use std::mem;
use std::ptr;
use std::raw;
use std::ptr::Unique;
use std::thunk::Invoke;
use std::ops::{Index, IndexMut};

/// The type representing a foreign chunk of memory
pub struct CVec<T> {
    base: Unique<T>,
    len: usize,
    dtor: Option<Box<Invoke<*mut T> + 'static>>
}

#[unsafe_destructor]
impl<T> Drop for CVec<T> {
    fn drop(&mut self) {
        match self.dtor.take() {
            None => (),
            Some(f) => f.invoke(*self.base),
        }
    }
}

impl<T> CVec<T> {
    /// Create a `CVec` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A unique pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: Unique<T>, len: usize) -> CVec<T> {
        assert!(*base != ptr::null_mut());
        CVec {
            base: base,
            len: len,
            dtor: None,
        }
    }

    /// Create a `CVec` from a foreign buffer, with a given length,
    /// and a function to run upon destruction.
    ///
    /// Panics if the given pointer is null.
    ///
    /// # Arguments
    ///
    /// * base - A unique pointer to a buffer
    /// * len - The number of elements in the buffer
    /// * dtor - A fn to run when the value is destructed, useful
    ///          for freeing the buffer, etc. `base` will be passed
    ///          to it as an argument.
    pub unsafe fn new_with_dtor<F>(base: Unique<T>,
                                   len: usize,
                                   dtor: F)
                                   -> CVec<T>
        where F : FnOnce(*mut T) + 'static
    {
        assert!(*base != ptr::null_mut());
        let dtor = Box::new(dtor);
        CVec {
            base: base,
            len: len,
            dtor: Some(dtor)
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: *self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Unwrap the pointer without running the destructor
    ///
    /// This method retrieves the underlying pointer, and in the process
    /// destroys the CVec but without running the destructor. A use case
    /// would be transferring ownership of the buffer to a C function, as
    /// in this case you would not want to run the destructor.
    ///
    /// Note that if you want to access the underlying pointer without
    /// cancelling the destructor, you can simply call `transmute` on the return
    /// value of `get(0)`.
    pub unsafe fn into_inner(mut self) -> *mut T {
        self.dtor = None;
        *self.base
    }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Convert to CSlice
    pub fn as_cslice(&self) -> CSlice<T> {
        CSlice {
            base: *self.base,
            len: self.len
        }
    }
}

impl<T> AsSlice<T> for CVec<T> {
    /// View the stored data as a slice.
    fn as_slice<'a>(&'a self) -> &'a [T] {
        unsafe {
            mem::transmute(raw::Slice { data: *self.base as *const T, len: self.len })
        }
    }
}

/// The type representing an 'unsafe' foreign chunk of memory
pub struct CSlice<T> {
    base: *mut T,
    len: usize
}

impl<T> CSlice<T> {
    /// Create a `CSlice` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A raw pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: *mut T, len: usize) -> CSlice<T> {
        assert!(base != ptr::null_mut());
        CSlice {
            base: base,
            len: len
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> AsSlice<T> for CSlice<T> {
    /// View the stored data as a slice.
    fn as_slice<'a>(&'a self) -> &'a [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }
}

impl<T> Index<usize> for CSlice<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        assert!(*_index < self.len);
        unsafe { &*self.base.offset(*_index as isize) }
    }
}

impl<T> IndexMut<usize> for CSlice<T> {
    fn index_mut<'a>(&'a mut self, _index: &usize) -> &'a mut T {
        assert!(*_index < self.len);
        unsafe { &mut *self.base.offset(*_index as isize) }
    }
}

#[cfg(test)]
mod tests {
    extern crate alloc;
    extern crate libc;

    use super::{CVec, CSlice};
    use std::ptr::{self, Unique};

    // allocation of CVec
    fn v_malloc(n: usize) -> CVec<u8> {
        unsafe {
            let mem: Unique<u8> = Unique::new(
                libc::malloc(n as libc::size_t) as *mut _);
            if (*mem).is_null() { alloc::oom() }

            CVec::new_with_dtor(mem, n,
                                |mem| { libc::free((mem) as *mut _); })
        }
    }

    // allocation of CSlice
    fn s_malloc(n: usize) -> CSlice<u8> {
        unsafe {
            let mem: *mut u8 = libc::malloc(n as libc::size_t) as *mut _;
            if mem.is_null() { alloc::oom() }

            CSlice::new(mem, n)
        }
    }

    #[test]
    fn vec_test_basic() {
        let mut cv = v_malloc(16);

        *cv.get_mut(3).unwrap() = 8;
        *cv.get_mut(4).unwrap() = 9;
        assert_eq!(*cv.get(3).unwrap(), 8);
        assert_eq!(*cv.get(4).unwrap(), 9);
        assert_eq!(cv.len(), 16);
    }

    #[test]
    fn slice_test_basic() {
        let mut cs = s_malloc(16);

        cs[3] = 8;
        cs[4] = 9;
        assert_eq!(cs[3], 8);
        assert_eq!(cs[4], 9);
        assert_eq!(cs.len(), 16);
    }

    #[test]
    #[should_fail]
    fn vec_test_panic_at_null() {
        unsafe {
            CVec::new(Unique::new(ptr::null_mut::<u8>()), 9);
        }
    }

    #[test]
    #[should_fail]
    fn slice_test_panic_at_null() {
        unsafe {
            CSlice::new(ptr::null_mut::<u8>(), 9);
        }
    }

    #[test]
    fn vec_test_overrun_get() {
        let cv = v_malloc(16);

        assert!(cv.get(17).is_none());
    }

    #[test]
    #[should_fail]
    fn slice_test_overrun_get() {
        let cs = s_malloc(16);

        assert!(cs[17] == 18);
    }

    #[test]
    fn vec_test_overrun_set() {
        let mut cv = v_malloc(16);

        assert!(cv.get_mut(17).is_none());
    }

    #[test]
    fn vec_test_unwrap() {
        unsafe {
            let cv = CVec::new_with_dtor(Unique::new(1 as *mut isize),
                                         0,
                                         |_| panic!("Don't run this destructor!"));
            let p = cv.into_inner();
            assert_eq!(p, 1 as *mut isize);
        }
    }

    #[test]
    fn vec_to_slice_test() {
        unsafe {
            let mut cv = v_malloc(2);

            *cv.get_mut(0).unwrap() = 10;
            *cv.get_mut(1).unwrap() = 12;
            let cs = cv.as_cslice();

            assert_eq!(cs[0], 10);
            assert_eq!(cs[1], 12);
        }
    }

    #[test]
    fn slice_to_vec_test() {
        let cv = v_malloc(2);
        let mut cs = cv.as_cslice();

        cs[0] = 13;
        cs[1] = 26;
        assert_eq!(*cv.get(0).unwrap(), 13);
        assert_eq!(*cv.get(1).unwrap(), 26);
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{dirname} */ r#"
NAME
    dirname - strip last component from file name

SYNOPSIS
    dirname [ -h | --help ] FILE...

DESCRIPTION
    Strip last component from file name.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        if let Some(end) = path.rfind(|c| c == '/') {
            println!("{}", &path[..end]);
        } else {
            println!(".");
        }
    }
}
<commit_msg>Simpler pattern<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{dirname} */ r#"
NAME
    dirname - strip last component from file name

SYNOPSIS
    dirname [ -h | --help ] FILE...

DESCRIPTION
    Strip last component from file name.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }

    for path in &parser.args[0..] {
        if let Some(end) = path.rfind('/') {
            println!("{}", &path[..end]);
        } else {
            println!(".");
        }
    }
}
<|endoftext|>


<commit_before>//Copyright 2016 secret-service-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

// implement custom errors
//
// Classes of errors:
// - Dbus (IO, validation)
// - crypto
// - parsing dbus output (dbus returns unrecognizable output). Sometimes it's
//     for if the index exists in the results vector, sometimes it's for whether
//     the value being parsed at that index is the right type. Along these lines
//     I'm currently using unwrap() for converting types, should these also return
//     Result?
//
//     Almost all custom errors are of this type. It's mostly an internal error,
//     unexpected behavior indicates something very wrong, so should it panic? Or
//     is it still better to bubble up?
// - locked (currently custom dbus error)
// - prompt dismissed (not an error?) (currently custom dbus error)

use dbus;
use std::error;
use std::fmt;

/// Result type often returned from methods that have SsError.
/// Fns in this library return ::Result<T> when using this alias.
// (This pattern is something I saw in hyper)
pub type Result<T> = ::std::result::Result<T, SsError>;

#[derive(Debug)]
pub enum SsError {
    Crypto(String),
    Dbus(dbus::Error),
    Locked,
    NoResult,
    Parse,
    Prompt,
}

impl fmt::Display for SsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt:: Result {
        match *self {
            // crypto error does not implement Display
            SsError::Crypto(_) => write!(f, "Crypto error: Invalid Length or Padding"),
            SsError::Dbus(ref err) => write!(f, "Dbus error: {}", err),
            SsError::Locked => write!(f, "SS Error: object locked"),
            SsError::NoResult => write!(f, "SS error: result not returned from SS API"),
            SsError::Parse => write!(f, "SS error: could not parse Dbus output"),
            SsError::Prompt => write!(f, "SS error: prompt dismissed"),
        }
    }
}

impl error::Error for SsError {
    fn description(&self) -> &str {
        match *self {
            SsError::Crypto(_) => "crypto: Invalid Length or Padding",
            SsError::Dbus(ref err) => err.description(),
            SsError::Locked => "Object locked",
            SsError::NoResult => "Result not returned from SS API",
            SsError::Parse => "Error parsing Dbus output",
            SsError::Prompt => "Prompt Dismissed",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SsError::Dbus(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<block_modes::BlockModeError> for SsError {
    fn from(err: block_modes::BlockModeError) -> SsError {
        SsError::Crypto("Block mode error".into())
    }
}

impl From<block_modes::InvalidKeyIvLength> for SsError {
    fn from(err: block_modes::InvalidKeyIvLength) -> SsError {
        SsError::Crypto("Invalid Key Iv Lengt".into())
    }
}

impl From<dbus::Error> for SsError {
    fn from(err: dbus::Error) -> SsError {
        SsError::Dbus(err)
    }
}

<commit_msg>cleanup warnings<commit_after>//Copyright 2016 secret-service-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

// implement custom errors
//
// Classes of errors:
// - Dbus (IO, validation)
// - crypto
// - parsing dbus output (dbus returns unrecognizable output). Sometimes it's
//     for if the index exists in the results vector, sometimes it's for whether
//     the value being parsed at that index is the right type. Along these lines
//     I'm currently using unwrap() for converting types, should these also return
//     Result?
//
//     Almost all custom errors are of this type. It's mostly an internal error,
//     unexpected behavior indicates something very wrong, so should it panic? Or
//     is it still better to bubble up?
// - locked (currently custom dbus error)
// - prompt dismissed (not an error?) (currently custom dbus error)

use dbus;
use std::error;
use std::fmt;

/// Result type often returned from methods that have SsError.
/// Fns in this library return ::Result<T> when using this alias.
// (This pattern is something I saw in hyper)
pub type Result<T> = ::std::result::Result<T, SsError>;

#[derive(Debug)]
pub enum SsError {
    Crypto(String),
    Dbus(dbus::Error),
    Locked,
    NoResult,
    Parse,
    Prompt,
}

impl fmt::Display for SsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt:: Result {
        match *self {
            // crypto error does not implement Display
            SsError::Crypto(_) => write!(f, "Crypto error: Invalid Length or Padding"),
            SsError::Dbus(ref err) => write!(f, "Dbus error: {}", err),
            SsError::Locked => write!(f, "SS Error: object locked"),
            SsError::NoResult => write!(f, "SS error: result not returned from SS API"),
            SsError::Parse => write!(f, "SS error: could not parse Dbus output"),
            SsError::Prompt => write!(f, "SS error: prompt dismissed"),
        }
    }
}

impl error::Error for SsError {
    fn description(&self) -> &str {
        match *self {
            SsError::Crypto(_) => "crypto: Invalid Length or Padding",
            SsError::Dbus(ref err) => err.description(),
            SsError::Locked => "Object locked",
            SsError::NoResult => "Result not returned from SS API",
            SsError::Parse => "Error parsing Dbus output",
            SsError::Prompt => "Prompt Dismissed",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SsError::Dbus(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<block_modes::BlockModeError> for SsError {
    fn from(_err: block_modes::BlockModeError) -> SsError {
        SsError::Crypto("Block mode error".into())
    }
}

impl From<block_modes::InvalidKeyIvLength> for SsError {
    fn from(_err: block_modes::InvalidKeyIvLength) -> SsError {
        SsError::Crypto("Invalid Key Iv Lengt".into())
    }
}

impl From<dbus::Error> for SsError {
    fn from(err: dbus::Error) -> SsError {
        SsError::Dbus(err)
    }
}

<|endoftext|>


<commit_before>//! A custom Goblin error
//!

use scroll;
use core::result;
use core::fmt::{self, Display};
use std::error;
use std::io;

#[derive(Debug)]
/// A custom Goblin error
pub enum Error {
    IO(io::Error),
    Scroll(scroll::Error),
    Malformed(String),
    BadMagic(u64),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IO(_) => { "IO error" }
            Error::Scroll(_) => { "Scroll error" }
            Error::BadMagic(_) => { "Invalid magic number" }
            Error::Malformed(_) => { "Entity is malformed in some way" }
        }
    }
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IO(ref io) => { io.cause() }
            Error::Scroll(ref scroll) => { scroll.cause() }
            Error::BadMagic(_) => { None }
            Error::Malformed(_) => { None }
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<scroll::Error> for Error {
    fn from(err: scroll::Error) -> Error {
        Error::Scroll(err)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::IO(ref err) => { write!(fmt, "{}", err) },
            Error::Scroll(ref err) => { write!(fmt, "{}", err) },
            Error::BadMagic(magic) => { write! (fmt, "Invalid magic number: 0x{:x}", magic) },
            Error::Malformed(ref msg) => { write! (fmt, "Malformed entity: {}", msg) },
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>error: document<commit_after>//! A custom Goblin error
//!

use scroll;
use core::result;
use core::fmt::{self, Display};
use std::error;
use std::io;

#[derive(Debug)]
/// A custom Goblin error
pub enum Error {
    /// An IO based error
    IO(io::Error),
    /// An error emanating from reading and interpreting bytes
    Scroll(scroll::Error),
    /// The binary is malformed somehow
    Malformed(String),
    /// The binary's magic is unknown or bad
    BadMagic(u64),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IO(_) => { "IO error" }
            Error::Scroll(_) => { "Scroll error" }
            Error::BadMagic(_) => { "Invalid magic number" }
            Error::Malformed(_) => { "Entity is malformed in some way" }
        }
    }
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IO(ref io) => { io.cause() }
            Error::Scroll(ref scroll) => { scroll.cause() }
            Error::BadMagic(_) => { None }
            Error::Malformed(_) => { None }
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<scroll::Error> for Error {
    fn from(err: scroll::Error) -> Error {
        Error::Scroll(err)
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::IO(ref err) => { write!(fmt, "{}", err) },
            Error::Scroll(ref err) => { write!(fmt, "{}", err) },
            Error::BadMagic(magic) => { write! (fmt, "Invalid magic number: 0x{:x}", magic) },
            Error::Malformed(ref msg) => { write! (fmt, "Malformed entity: {}", msg) },
        }
    }
}

/// An impish result
pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use alloc::fmt;
use alloc::string::String;
use core::result;
use std::error::Error as StdError;
use std::io::Error as IoError;

pub type Result<T> = result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug, Clone)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported in non-lossless coding process.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc) => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err) => err.fmt(f),
            Error::Internal(ref err) => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<commit_msg>Add `PartialEq, Eq, Hash` as `TiffUnsupportedError` implements this<commit_after>use alloc::boxed::Box;
use alloc::fmt;
use alloc::string::String;
use core::result;
use std::error::Error as StdError;
use std::io::Error as IoError;

pub type Result<T> = result::Result<T, Error>;

/// An enumeration over JPEG features (currently) unsupported by this library.
///
/// Support for features listed here may be included in future versions of this library.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum UnsupportedFeature {
    /// Hierarchical JPEG.
    Hierarchical,
    /// JPEG using arithmetic entropy coding instead of Huffman coding.
    ArithmeticEntropyCoding,
    /// Sample precision in bits. 8 bit sample precision is what is currently supported in non-lossless coding process.
    SamplePrecision(u8),
    /// Number of components in an image. 1, 3 and 4 components are currently supported.
    ComponentCount(u8),
    /// An image can specify a zero height in the frame header and use the DNL (Define Number of
    /// Lines) marker at the end of the first scan to define the number of lines in the frame.
    DNL,
    /// Subsampling ratio.
    SubsamplingRatio,
    /// A subsampling ratio not representable as an integer.
    NonIntegerSubsamplingRatio,
}

/// Errors that can occur while decoding a JPEG image.
#[derive(Debug)]
pub enum Error {
    /// The image is not formatted properly. The string contains detailed information about the
    /// error.
    Format(String),
    /// The image makes use of a JPEG feature not (currently) supported by this library.
    Unsupported(UnsupportedFeature),
    /// An I/O error occurred while decoding the image.
    Io(IoError),
    /// An internal error occurred while decoding the image.
    Internal(Box<dyn StdError + Send + Sync + 'static>), //TODO: not used, can be removed with the next version bump
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Format(ref desc) => write!(f, "invalid JPEG format: {}", desc),
            Error::Unsupported(ref feat) => write!(f, "unsupported JPEG feature: {:?}", feat),
            Error::Io(ref err) => err.fmt(f),
            Error::Internal(ref err) => err.fmt(f),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Internal(ref err) => Some(&**err),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use {IntoRawMode, TerminalError};

/// Extension to `Read` trait.
pub trait ReadExt {
    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the password input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> Result<Option<String>, TerminalError>;
}

impl<R: Read> ReadExt for R {
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> Result<Option<String>, TerminalError> {
        let _raw = try!(writer.into_raw_mode());
        let mut string = String::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(_) => return Err(TerminalError::StdinError),
                Ok(b'\0') | Ok(b'\x03') | Ok(b'\x04') => return Ok(None),
                Ok(b'\n') | Ok(b'\r') => return Ok(Some(string)),
                Ok(c) => string.push(c as char),
            }
        }

        Ok(Some(string))
    }
}
<commit_msg>Amend #1 to use direct integers instead of byte chars<commit_after>use std::io::{Read, Write};
use {IntoRawMode, TerminalError};

/// Extension to `Read` trait.
pub trait ReadExt {
    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the password input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> Result<Option<String>, TerminalError>;
}

impl<R: Read> ReadExt for R {
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> Result<Option<String>, TerminalError> {
        let _raw = try!(writer.into_raw_mode());
        let mut string = String::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(_) => return Err(TerminalError::StdinError),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(b'\n') | Ok(b'\r') => return Ok(Some(string)),
                Ok(c) => string.push(c as char),
            }
        }

        Ok(Some(string))
    }
}
<|endoftext|>