<commit_before>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod cmd_finder;

use std::env;
use std::env::consts;
use std::fs;
use std::path::{Path, PathBuf};

static SHADERC_STATIC_LIB: &str = "shaderc_combined";
static SHADERC_SHARED_LIB: &str = "shaderc_shared";
static SHADERC_STATIC_LIB_FILE_UNIX: &str = "libshaderc_combined.a";
static SHADERC_STATIC_LIB_FILE_WIN: &str = "shaderc_combined.lib";

fn get_apple_sdk_path() -> Option<PathBuf> {
    let target = std::env::var("TARGET").unwrap();
    use std::process::Command;

    // tvOS (and the simulator) could be added here in the future.
    let sdk = if target == "x86_64-apple-ios" || target == "i386-apple-ios" {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        return None;
    };

    let output = if let Ok(out) = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()
    {
        out.stdout
    } else {
        return None;
    };
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Some(PathBuf::from(prefix_str.trim_end().to_string()))
}

fn build_shaderc_unix(shaderc_dir: &PathBuf, use_ninja: bool, target_os: String) -> PathBuf {
    let mut config = cmake::Config::new(shaderc_dir);
    config
        .profile("Release")
        // CMake options
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
        // Glslang options
        .define("ENABLE_SPVREMAPPER", "OFF")
        .define("ENABLE_GLSLANG_BINARIES", "OFF")
        // Shaderc options
        .define("SHADERC_SKIP_TESTS", "ON")
        // SPIRV-Tools options
        .define("SPIRV_SKIP_EXECUTABLES", "ON")
        .define("SPIRV_WERROR", "OFF");
    if use_ninja {
        config.generator("Ninja");
    }

    if target_os == "ios" {
        if let Some(path) = get_apple_sdk_path() {
            config.define("CMAKE_OSX_SYSROOT", path);
        }
    }

    config.build()
}

fn build_shaderc_msvc(shaderc_dir: &PathBuf) -> PathBuf {
    let linkage = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();

    let mut config = cmake::Config::new(shaderc_dir);
    config
        .profile("Release")
        // CMake options
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
        // Glslang options
        .define("ENABLE_SPVREMAPPER", "OFF")
        .define("ENABLE_GLSLANG_BINARIES", "OFF")
        // Shaderc options
        .define("SHADERC_SKIP_TESTS", "ON")
        // SPIRV-Tools options
        .define("SPIRV_SKIP_EXECUTABLES", "ON")
        .define("SPIRV_WERROR", "OFF")
        .generator("Ninja");

    // cmake-rs tries to be clever on Windows by injecting several
    // C/C++ flags, which causes problems. So I have to manually
    // define CMAKE_*_FLAGS_* here to suppress that.
    let config = if linkage.contains("crt-static") {
        // statically-linked CRT
        config
            .define("CMAKE_C_FLAGS", " /nologo /EHsc /MT")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc /MT")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc /MT")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc /MT")
    } else {
        // dynamically-linked CRT
        config
            .define("CMAKE_C_FLAGS", " /nologo /EHsc /MD")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc /MD")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc /MD")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc /MD")
            // prevent shaderc's cmake script messes with crt flags
            .define("SHADERC_ENABLE_SHARED_CRT", "ON")
    };

    config.build()
}

fn main() {
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    let config_build_from_source = env::var("CARGO_FEATURE_BUILD_FROM_SOURCE").is_ok();
    let has_explicit_set_search_dir = env::var("SHADERC_LIB_DIR").is_ok();

    // Initialize explicit shaderc search directory first.
    let mut search_dir = if let Ok(lib_dir) = env::var("SHADERC_LIB_DIR") {
        println!(
            "cargo:warning=shaderc: searching native shaderc libraries in '{}'",
            lib_dir
        );
        Some(lib_dir)
    } else {
        None
    };

    // Try to find native shaderc library from Vulkan SDK if possible.
    if search_dir.is_none() {
        search_dir = if let Ok(sdk_dir) = env::var("VULKAN_SDK") {
            println!(
                "cargo:warning=shaderc: searching native shaderc libraries in Vulkan SDK '{}/lib'",
                sdk_dir
            );
            Some(format!("{}/lib/", sdk_dir))
        } else {
            None
        };
    }

    // If no explicit path is set and no explicit request is made to build from
    // source, check known system locations before falling back to build from source.
    // This set `search_dir` for later usage.
    if search_dir.is_none() && !config_build_from_source {
        println!(
            "cargo:warning=shaderc: searching for native shaderc libraries on system;  \
             use '--features build-from-source' to force building from source code"
        );

        if target_os == "macos" {
            // Vulkan SDK is installed in `/usr/local/` by default on macOS
            let macos_path = "/usr/local/lib/";
            if Path::new(macos_path).exists() {
                search_dir = Some(macos_path.to_owned());
            }
        } else if target_os == "linux" {
            // https://wiki.ubuntu.com/MultiarchSpec
            // https://wiki.debian.org/Multiarch/Implementation
            let debian_arch = match env::var("CARGO_CFG_TARGET_ARCH").unwrap() {
                arch if arch == "x86" => "i386".to_owned(),
                arch => arch,
            };
            let debian_triple_path = format!("/usr/lib/{}-linux-gnu/", debian_arch);

            search_dir = if Path::new(&debian_triple_path).exists() {
                // Debian, Ubuntu and their derivatives.
                Some(debian_triple_path)
            } else if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86_64"
                && Path::new("/usr/lib64/").exists()
            {
                // Other distributions running on x86_64 usually use this path.
                Some("/usr/lib64/".to_owned())
            } else {
                // Other distributions, not x86_64.
                Some("/usr/lib/".to_owned())
            };
        }
    }

    // Canonicalize the sarch directory first.
    let search_dir = if let Some(search_dir) = search_dir {
        let path = Path::new(&search_dir);
        let cannonical = fs::canonicalize(&path);
        if path.is_relative() {
            println!(
                "cargo:warning=shaderc: the given search path '{:?}' is relative; \
                 path must be relative to shaderc-sys crate, \
                 likely not your current working directory",
                &path
            );
        } else if !path.is_dir() {
            println!(
                "cargo:warning=shaderc: the given search path '{:?}' is not a directory",
                &path
            );
        }
        if (cannonical.is_err()) && has_explicit_set_search_dir {
            println!("cargo:warning=shaderc: {:?}", cannonical.err().unwrap());
            println!(
                "cargo:warning=shaderc: failed to canonicalize the given search path '{:?}'",
                &path
            );
            None
        } else {
            cannonical.ok()
        }
    } else {
        None
    };

    // Try to build with the dynamic or static library if a path was explicit set
    // or implicitly chosen.
    if let Some(search_dir) = search_dir {
        let search_dir_str = search_dir.to_string_lossy();

        let static_lib_path = search_dir.join(if target_os == "windows" && target_env == "msvc" {
            SHADERC_STATIC_LIB_FILE_WIN
        } else {
            SHADERC_STATIC_LIB_FILE_UNIX
        });

        let dylib_name = format!(
            "{}{}{}",
            consts::DLL_PREFIX,
            SHADERC_SHARED_LIB,
            consts::DLL_SUFFIX
        );
        let dylib_path = search_dir.join(dylib_name);

        if let Some((lib_name, lib_kind)) = {
            if dylib_path.exists() {
                Some((SHADERC_SHARED_LIB, "dylib"))
            } else if static_lib_path.exists() {
                Some((SHADERC_STATIC_LIB, "static"))
            } else {
                None
            }
        } {
            match (target_os.as_str(), target_env.as_str()) {
                ("linux", _) => {
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=stdc++");
                    return;
                }
                ("windows", "msvc") => {
                    println!("cargo:warning=shaderc: Windows MSVC static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    return;
                }
                ("windows", "gnu") => {
                    println!("cargo:warning=shaderc: Windows MinGW static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=stdc++");
                    return;
                }
                ("macos", _) => {
                    println!("cargo:warning=shaderc: macOS static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=c++");
                    return;
                }
                ("ios", _) => {
                    println!("cargo:warning=shaderc: macOS static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=c++");
                    return;
                }
                (_, _) => {
                    println!(
                        "cargo:warning=shaderc: unsupported platform for linking against \
                         native shaderc libraries installed on system"
                    );
                }
            }
        }
    }

    if config_build_from_source {
        println!("cargo:warning=shaderc: requested to build from source");
    } else {
        println!(
            "cargo:warning=shaderc: cannot find native shaderc library on system; \
             falling back to build from source"
        );
    }

    let mut finder = cmd_finder::CommandFinder::new();

    finder.must_have("cmake");
    finder.must_have("git");
    finder
        .maybe_have("python3")
        .or(finder.maybe_have("python"))
        .unwrap_or_else(|| {
            panic!("Build requires one of `python3` or `python`");
        });

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let shaderc_dir = Path::new(&manifest_dir).join("build");

    let mut lib_path = if target_env == "msvc" {
        finder.must_have("ninja");
        build_shaderc_msvc(&shaderc_dir)
    } else {
        let has_ninja = finder.maybe_have("ninja").is_some();
        build_shaderc_unix(&shaderc_dir, has_ninja, target_os)
    };

    lib_path.push("lib");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
    println!("cargo:rustc-link-lib=static={}", SHADERC_STATIC_LIB);

    emit_std_cpp_link();
}

fn emit_std_cpp_link() {
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

    match (target_os.as_str(), target_env.as_str()) {
        ("linux", _) | ("windows", "gnu") => println!("cargo:rustc-link-lib=dylib=stdc++"),
        ("macos", _) => println!("cargo:rustc-link-lib=dylib=c++"),
        _ => {}
    }
}
<commit_msg>Fix iOS aarch64 simulator detection (#110)<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod cmd_finder;

use std::env;
use std::env::consts;
use std::fs;
use std::path::{Path, PathBuf};

static SHADERC_STATIC_LIB: &str = "shaderc_combined";
static SHADERC_SHARED_LIB: &str = "shaderc_shared";
static SHADERC_STATIC_LIB_FILE_UNIX: &str = "libshaderc_combined.a";
static SHADERC_STATIC_LIB_FILE_WIN: &str = "shaderc_combined.lib";

fn get_apple_sdk_path() -> Option<PathBuf> {
    let target = std::env::var("TARGET").unwrap();
    use std::process::Command;

    // tvOS (and the simulator) could be added here in the future.
    let sdk = if target == "x86_64-apple-ios"
        || target == "i386-apple-ios"
        || target == "aarch64-apple-ios-sim"
    {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        return None;
    };

    let output = if let Ok(out) = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()
    {
        out.stdout
    } else {
        return None;
    };
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Some(PathBuf::from(prefix_str.trim_end().to_string()))
}

fn build_shaderc_unix(shaderc_dir: &PathBuf, use_ninja: bool, target_os: String) -> PathBuf {
    let mut config = cmake::Config::new(shaderc_dir);
    config
        .profile("Release")
        // CMake options
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
        // Glslang options
        .define("ENABLE_SPVREMAPPER", "OFF")
        .define("ENABLE_GLSLANG_BINARIES", "OFF")
        // Shaderc options
        .define("SHADERC_SKIP_TESTS", "ON")
        // SPIRV-Tools options
        .define("SPIRV_SKIP_EXECUTABLES", "ON")
        .define("SPIRV_WERROR", "OFF");
    if use_ninja {
        config.generator("Ninja");
    }

    if target_os == "ios" {
        if let Some(path) = get_apple_sdk_path() {
            config.define("CMAKE_OSX_SYSROOT", path);
        }
    }

    config.build()
}

fn build_shaderc_msvc(shaderc_dir: &PathBuf) -> PathBuf {
    let linkage = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();

    let mut config = cmake::Config::new(shaderc_dir);
    config
        .profile("Release")
        // CMake options
        .define("CMAKE_INSTALL_LIBDIR", "lib")
        .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
        // Glslang options
        .define("ENABLE_SPVREMAPPER", "OFF")
        .define("ENABLE_GLSLANG_BINARIES", "OFF")
        // Shaderc options
        .define("SHADERC_SKIP_TESTS", "ON")
        // SPIRV-Tools options
        .define("SPIRV_SKIP_EXECUTABLES", "ON")
        .define("SPIRV_WERROR", "OFF")
        .generator("Ninja");

    // cmake-rs tries to be clever on Windows by injecting several
    // C/C++ flags, which causes problems. So I have to manually
    // define CMAKE_*_FLAGS_* here to suppress that.
    let config = if linkage.contains("crt-static") {
        // statically-linked CRT
        config
            .define("CMAKE_C_FLAGS", " /nologo /EHsc /MT")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc /MT")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc /MT")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc /MT")
    } else {
        // dynamically-linked CRT
        config
            .define("CMAKE_C_FLAGS", " /nologo /EHsc /MD")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc /MD")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc /MD")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc /MD")
            // prevent shaderc's cmake script messes with crt flags
            .define("SHADERC_ENABLE_SHARED_CRT", "ON")
    };

    config.build()
}

fn main() {
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    let config_build_from_source = env::var("CARGO_FEATURE_BUILD_FROM_SOURCE").is_ok();
    let has_explicit_set_search_dir = env::var("SHADERC_LIB_DIR").is_ok();

    // Initialize explicit shaderc search directory first.
    let mut search_dir = if let Ok(lib_dir) = env::var("SHADERC_LIB_DIR") {
        println!(
            "cargo:warning=shaderc: searching native shaderc libraries in '{}'",
            lib_dir
        );
        Some(lib_dir)
    } else {
        None
    };

    // Try to find native shaderc library from Vulkan SDK if possible.
    if search_dir.is_none() {
        search_dir = if let Ok(sdk_dir) = env::var("VULKAN_SDK") {
            println!(
                "cargo:warning=shaderc: searching native shaderc libraries in Vulkan SDK '{}/lib'",
                sdk_dir
            );
            Some(format!("{}/lib/", sdk_dir))
        } else {
            None
        };
    }

    // If no explicit path is set and no explicit request is made to build from
    // source, check known system locations before falling back to build from source.
    // This set `search_dir` for later usage.
    if search_dir.is_none() && !config_build_from_source {
        println!(
            "cargo:warning=shaderc: searching for native shaderc libraries on system;  \
             use '--features build-from-source' to force building from source code"
        );

        if target_os == "macos" {
            // Vulkan SDK is installed in `/usr/local/` by default on macOS
            let macos_path = "/usr/local/lib/";
            if Path::new(macos_path).exists() {
                search_dir = Some(macos_path.to_owned());
            }
        } else if target_os == "linux" {
            // https://wiki.ubuntu.com/MultiarchSpec
            // https://wiki.debian.org/Multiarch/Implementation
            let debian_arch = match env::var("CARGO_CFG_TARGET_ARCH").unwrap() {
                arch if arch == "x86" => "i386".to_owned(),
                arch => arch,
            };
            let debian_triple_path = format!("/usr/lib/{}-linux-gnu/", debian_arch);

            search_dir = if Path::new(&debian_triple_path).exists() {
                // Debian, Ubuntu and their derivatives.
                Some(debian_triple_path)
            } else if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86_64"
                && Path::new("/usr/lib64/").exists()
            {
                // Other distributions running on x86_64 usually use this path.
                Some("/usr/lib64/".to_owned())
            } else {
                // Other distributions, not x86_64.
                Some("/usr/lib/".to_owned())
            };
        }
    }

    // Canonicalize the sarch directory first.
    let search_dir = if let Some(search_dir) = search_dir {
        let path = Path::new(&search_dir);
        let cannonical = fs::canonicalize(&path);
        if path.is_relative() {
            println!(
                "cargo:warning=shaderc: the given search path '{:?}' is relative; \
                 path must be relative to shaderc-sys crate, \
                 likely not your current working directory",
                &path
            );
        } else if !path.is_dir() {
            println!(
                "cargo:warning=shaderc: the given search path '{:?}' is not a directory",
                &path
            );
        }
        if (cannonical.is_err()) && has_explicit_set_search_dir {
            println!("cargo:warning=shaderc: {:?}", cannonical.err().unwrap());
            println!(
                "cargo:warning=shaderc: failed to canonicalize the given search path '{:?}'",
                &path
            );
            None
        } else {
            cannonical.ok()
        }
    } else {
        None
    };

    // Try to build with the dynamic or static library if a path was explicit set
    // or implicitly chosen.
    if let Some(search_dir) = search_dir {
        let search_dir_str = search_dir.to_string_lossy();

        let static_lib_path = search_dir.join(if target_os == "windows" && target_env == "msvc" {
            SHADERC_STATIC_LIB_FILE_WIN
        } else {
            SHADERC_STATIC_LIB_FILE_UNIX
        });

        let dylib_name = format!(
            "{}{}{}",
            consts::DLL_PREFIX,
            SHADERC_SHARED_LIB,
            consts::DLL_SUFFIX
        );
        let dylib_path = search_dir.join(dylib_name);

        if let Some((lib_name, lib_kind)) = {
            if dylib_path.exists() {
                Some((SHADERC_SHARED_LIB, "dylib"))
            } else if static_lib_path.exists() {
                Some((SHADERC_STATIC_LIB, "static"))
            } else {
                None
            }
        } {
            match (target_os.as_str(), target_env.as_str()) {
                ("linux", _) => {
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=stdc++");
                    return;
                }
                ("windows", "msvc") => {
                    println!("cargo:warning=shaderc: Windows MSVC static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    return;
                }
                ("windows", "gnu") => {
                    println!("cargo:warning=shaderc: Windows MinGW static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=stdc++");
                    return;
                }
                ("macos", _) => {
                    println!("cargo:warning=shaderc: macOS static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=c++");
                    return;
                }
                ("ios", _) => {
                    println!("cargo:warning=shaderc: macOS static build is experimental");
                    println!("cargo:rustc-link-search=native={}", search_dir_str);
                    println!("cargo:rustc-link-lib={}={}", lib_kind, lib_name);
                    println!("cargo:rustc-link-lib=dylib=c++");
                    return;
                }
                (_, _) => {
                    println!(
                        "cargo:warning=shaderc: unsupported platform for linking against \
                         native shaderc libraries installed on system"
                    );
                }
            }
        }
    }

    if config_build_from_source {
        println!("cargo:warning=shaderc: requested to build from source");
    } else {
        println!(
            "cargo:warning=shaderc: cannot find native shaderc library on system; \
             falling back to build from source"
        );
    }

    let mut finder = cmd_finder::CommandFinder::new();

    finder.must_have("cmake");
    finder.must_have("git");
    finder
        .maybe_have("python3")
        .or(finder.maybe_have("python"))
        .unwrap_or_else(|| {
            panic!("Build requires one of `python3` or `python`");
        });

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let shaderc_dir = Path::new(&manifest_dir).join("build");

    let mut lib_path = if target_env == "msvc" {
        finder.must_have("ninja");
        build_shaderc_msvc(&shaderc_dir)
    } else {
        let has_ninja = finder.maybe_have("ninja").is_some();
        build_shaderc_unix(&shaderc_dir, has_ninja, target_os)
    };

    lib_path.push("lib");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
    println!("cargo:rustc-link-lib=static={}", SHADERC_STATIC_LIB);

    emit_std_cpp_link();
}

fn emit_std_cpp_link() {
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

    match (target_os.as_str(), target_env.as_str()) {
        ("linux", _) | ("windows", "gnu") => println!("cargo:rustc-link-lib=dylib=stdc++"),
        ("macos", _) => println!("cargo:rustc-link-lib=dylib=c++"),
        _ => {}
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! A multiplexed cita protocol

use byteorder::{ByteOrder, NetworkEndian};
use bytes::BufMut;
use bytes::BytesMut;
use logger::{error, warn};
use std::io;
use std::str;
use tokio::codec::{Decoder, Encoder};

pub type CitaRequest = (String, Vec<u8>);
pub type CitaResponse = Option<(String, Vec<u8>)>;

/// Our multiplexed line-based codec
pub struct CitaCodec;

/// Implementation of the multiplexed line-based protocol.
///
/// Frames begin with a 4 byte header, consisting of the numeric request ID
/// encoded in network order, followed by the frame payload encoded as a UTF-8
/// string and terminated with a '\n' character:
///
/// # An example frame:
///
/// +------------------------+--------------------------+
/// | Type                   | Content                  |
/// +------------------------+--------------------------+
/// | Symbol for Start       | \xDEADBEEF               |
/// | Length of Full Payload | u32                      |
/// +------------------------+--------------------------+
/// | Length of Key          | u8                       |
/// | Key                    | bytes of a str           |
/// +------------------------+--------------------------+
/// | Message                | a serialize data         |
/// +------------------------+--------------------------+
///

// Start of network messages.
const NETMSG_START: u64 = 0xDEAD_BEEF_0000_0000;

// According to CITA frame, defines its frame header length as:
// "Symbol for Start" + "Length of Full Payload" + "Length of Key",
// And this will consume "4 + 4 + 1" fixed-lengths of the frame.
pub const CITA_FRAME_HEADER_LEN: usize = 4 + 4 + 1;

fn opt_bytes_extend(buf: &mut BytesMut, data: &[u8]) {
    buf.reserve(data.len());
    unsafe {
        buf.bytes_mut()[..data.len()].copy_from_slice(data);
        buf.advance_mut(data.len());
    }
}

impl Decoder for CitaCodec {
    type Item = CitaRequest;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        Ok(network_message_to_pubsub_message(buf))
    }
}

impl Encoder for CitaCodec {
    type Item = CitaResponse;
    type Error = io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut BytesMut) -> io::Result<()> {
        pubsub_message_to_network_message(buf, msg);
        Ok(())
    }
}

pub fn pubsub_message_to_network_message(buf: &mut BytesMut, msg: Option<(String, Vec<u8>)>) {
    let mut request_id_bytes = [0; 8];
    if let Some((key, body)) = msg {
        let length_key = key.len();
        // Use 1 byte to store key length.
        if length_key > u8::max_value() as usize {
            error!("[CitaProtocol] The MQ message key is too long {}.", key);
            return;
        }
        // Use 1 bytes to store the length for key, then store key, the last part is body.
        let length_full = 1 + length_key + body.len();
        if length_full > u32::max_value() as usize {
            error!(
                "[CitaProtocol] The MQ message with key {} is too long {}.",
                key,
                body.len()
            );
            return;
        }
        let request_id = NETMSG_START + length_full as u64;
        NetworkEndian::write_u64(&mut request_id_bytes, request_id);
        opt_bytes_extend(buf, &request_id_bytes);
        buf.put_u8(length_key as u8);
        opt_bytes_extend(buf, key.as_bytes());
        opt_bytes_extend(buf, &body);
    } else {
        let request_id = NETMSG_START;
        NetworkEndian::write_u64(&mut request_id_bytes, request_id);
        opt_bytes_extend(buf, &request_id_bytes);
    }
}

pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option<(String, Vec<u8>)> {
    if buf.len() < 8 {
        return None;
    }

    let request_id = NetworkEndian::read_u64(buf.as_ref());
    let netmsg_start = request_id & 0xffff_ffff_0000_0000;
    let length_full = (request_id & 0x0000_0000_ffff_ffff) as usize;
    if netmsg_start != NETMSG_START {
        return None;
    }
    if length_full + 8 > buf.len() {
        return None;
    }
    let _request_id_buf = buf.split_to(8);

    if length_full == 0 {
        return None;
    }
    let mut payload_buf = buf.split_to(length_full);

    let length_key = payload_buf[0] as usize;
    let _length_key_buf = payload_buf.split_to(1);
    if length_key == 0 {
        error!("[CitaProtocol] Network message key is empty.");
        return None;
    }
    if length_key > payload_buf.len() {
        error!(
            "[CitaProtocol] Buffer is not enough for key {} > {}.",
            length_key,
            buf.len()
        );
        return None;
    }
    let key_buf = payload_buf.split_to(length_key);
    let key_str_result = str::from_utf8(&key_buf);
    if key_str_result.is_err() {
        error!(
            "[CitaProtocol] Network message parse key error {:?}.",
            key_buf
        );
        return None;
    }
    let key = key_str_result.unwrap().to_string();
    if length_full == 1 + length_key {
        warn!("[CitaProtocol] Network message is empty.");
    }
    Some((key, payload_buf.to_vec()))
}

#[cfg(test)]
mod test {
    use super::{network_message_to_pubsub_message, pubsub_message_to_network_message};
    use bytes::BytesMut;

    #[test]
    fn convert_empty_message() {
        let mut buf = BytesMut::with_capacity(4 + 4);
        pubsub_message_to_network_message(&mut buf, None);
        let pub_msg_opt = network_message_to_pubsub_message(&mut buf);
        assert!(pub_msg_opt.is_none());
    }

    #[test]
    fn convert_messages() {
        let key = "this-is-the-key".to_string();
        let msg: Vec<u8> = vec![1, 3, 5, 7, 9];
        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + key.len() + msg.len());
        pubsub_message_to_network_message(&mut buf, Some((key.clone(), msg.clone())));
        let pub_msg_opt = network_message_to_pubsub_message(&mut buf);
        assert!(pub_msg_opt.is_some());
        let (key_new, msg_new) = pub_msg_opt.unwrap();
        assert_eq!(key, key_new);
        assert_eq!(msg, msg_new);
    }
}
<commit_msg>delete useless code<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! A multiplexed cita protocol

use byteorder::{ByteOrder, NetworkEndian};
use bytes::BufMut;
use bytes::BytesMut;
use logger::{error, warn};
use std::str;

/// Implementation of the multiplexed line-based protocol.
///
/// Frames begin with a 4 byte header, consisting of the numeric request ID
/// encoded in network order, followed by the frame payload encoded as a UTF-8
/// string and terminated with a '\n' character:
///
/// # An example frame:
///
/// +------------------------+--------------------------+
/// | Type                   | Content                  |
/// +------------------------+--------------------------+
/// | Symbol for Start       | \xDEADBEEF               |
/// | Length of Full Payload | u32                      |
/// +------------------------+--------------------------+
/// | Length of Key          | u8                       |
/// | Key                    | bytes of a str           |
/// +------------------------+--------------------------+
/// | Message                | a serialize data         |
/// +------------------------+--------------------------+
///

// Start of network messages.
const NETMSG_START: u64 = 0xDEAD_BEEF_0000_0000;

// According to CITA frame, defines its frame header length as:
// "Symbol for Start" + "Length of Full Payload" + "Length of Key",
// And this will consume "4 + 4 + 1" fixed-lengths of the frame.
pub const CITA_FRAME_HEADER_LEN: usize = 4 + 4 + 1;

fn opt_bytes_extend(buf: &mut BytesMut, data: &[u8]) {
    buf.reserve(data.len());
    unsafe {
        buf.bytes_mut()[..data.len()].copy_from_slice(data);
        buf.advance_mut(data.len());
    }
}

pub fn pubsub_message_to_network_message(buf: &mut BytesMut, msg: Option<(String, Vec<u8>)>) {
    let mut request_id_bytes = [0; 8];
    if let Some((key, body)) = msg {
        let length_key = key.len();
        // Use 1 byte to store key length.
        if length_key > u8::max_value() as usize {
            error!("[CitaProtocol] The MQ message key is too long {}.", key);
            return;
        }
        // Use 1 bytes to store the length for key, then store key, the last part is body.
        let length_full = 1 + length_key + body.len();
        if length_full > u32::max_value() as usize {
            error!(
                "[CitaProtocol] The MQ message with key {} is too long {}.",
                key,
                body.len()
            );
            return;
        }
        let request_id = NETMSG_START + length_full as u64;
        NetworkEndian::write_u64(&mut request_id_bytes, request_id);
        opt_bytes_extend(buf, &request_id_bytes);
        buf.put_u8(length_key as u8);
        opt_bytes_extend(buf, key.as_bytes());
        opt_bytes_extend(buf, &body);
    } else {
        let request_id = NETMSG_START;
        NetworkEndian::write_u64(&mut request_id_bytes, request_id);
        opt_bytes_extend(buf, &request_id_bytes);
    }
}

pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option<(String, Vec<u8>)> {
    if buf.len() < 8 {
        return None;
    }

    let request_id = NetworkEndian::read_u64(buf.as_ref());
    let netmsg_start = request_id & 0xffff_ffff_0000_0000;
    let length_full = (request_id & 0x0000_0000_ffff_ffff) as usize;
    if netmsg_start != NETMSG_START {
        return None;
    }
    if length_full + 8 > buf.len() {
        return None;
    }
    let _request_id_buf = buf.split_to(8);

    if length_full == 0 {
        return None;
    }
    let mut payload_buf = buf.split_to(length_full);

    let length_key = payload_buf[0] as usize;
    let _length_key_buf = payload_buf.split_to(1);
    if length_key == 0 {
        error!("[CitaProtocol] Network message key is empty.");
        return None;
    }
    if length_key > payload_buf.len() {
        error!(
            "[CitaProtocol] Buffer is not enough for key {} > {}.",
            length_key,
            buf.len()
        );
        return None;
    }
    let key_buf = payload_buf.split_to(length_key);
    let key_str_result = str::from_utf8(&key_buf);
    if key_str_result.is_err() {
        error!(
            "[CitaProtocol] Network message parse key error {:?}.",
            key_buf
        );
        return None;
    }
    let key = key_str_result.unwrap().to_string();
    if length_full == 1 + length_key {
        warn!("[CitaProtocol] Network message is empty.");
    }
    Some((key, payload_buf.to_vec()))
}

#[cfg(test)]
mod test {
    use super::{network_message_to_pubsub_message, pubsub_message_to_network_message};
    use bytes::BytesMut;

    #[test]
    fn convert_empty_message() {
        let mut buf = BytesMut::with_capacity(4 + 4);
        pubsub_message_to_network_message(&mut buf, None);
        let pub_msg_opt = network_message_to_pubsub_message(&mut buf);
        assert!(pub_msg_opt.is_none());
    }

    #[test]
    fn convert_messages() {
        let key = "this-is-the-key".to_string();
        let msg: Vec<u8> = vec![1, 3, 5, 7, 9];
        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + key.len() + msg.len());
        pubsub_message_to_network_message(&mut buf, Some((key.clone(), msg.clone())));
        let pub_msg_opt = network_message_to_pubsub_message(&mut buf);
        assert!(pub_msg_opt.is_some());
        let (key_new, msg_new) = pub_msg_opt.unwrap();
        assert_eq!(key, key_new);
        assert_eq!(msg, msg_new);
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => {
            help(commands);
            exit(0);
        },
    };

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&find_args(s)[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<commit_msg>Fixed bug where flags would not be read<commit_after>extern crate crossbeam;
#[macro_use] extern crate version;
extern crate walkdir;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .map(String::from)
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn find_command() -> Option<String> {
    env::args().skip(1).filter(|x| !x.starts_with("-")).next()
}

fn find_flag() -> Option<String> {
    env::args().skip(1).filter(|x| x.starts_with("-")).next()
}

fn find_args(command: &str) -> Vec<String> {
    env::args()
        .skip(1)
        .position(|e| e == command)
        .map(|pos| env::args().skip(pos + 2).collect::<Vec<String>>())
        .unwrap_or(vec![])
}

fn main() {
    let commands  = get_commands();
    let mut args  = env::args();
    let _         = args.next();
    let first_arg = match find_command() {
        Some(s) => s,
        None    => match find_flag() {
            Some(s) => s,
            None => {
                help(commands);
                exit(0);
            },
        },
    };

    match &first_arg[..] {
        "--help" | "-h" => {
            help(commands);
            exit(0);
        },

        "--version"  => println!("imag {}", &version!()[..]),

        "--versions" => {
            let mut result = vec![];
            for command in commands.iter() {
                result.push(crossbeam::scope(|scope| {
                    scope.spawn(|| {
                        let v = Command::new(command).arg("--version").output();
                        match v {
                            Ok(v) => match String::from_utf8(v.stdout) {
                                Ok(s) => format!("{} -> {}", command, s),
                                Err(e) => format!("Failed calling {} -> {:?}", command, e),
                            },
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        }
                    })
                }))
            }

            for versionstring in result.into_iter().map(|handle| handle.join()) {
                println!("{}", versionstring);
            }
        },

        s => {
            match Command::new(format!("imag-{}", s))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&find_args(s)[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        println!("{} exited with non-zero exit code", s);
                        exit(exit_status.code().unwrap_or(42));
                    }
                },

                Err(e) => {
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", s);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", s);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }

        },
    }
}
<|endoftext|>


<commit_before>use std::slice::Iter;

use Tree;
use Node;
use NodeId;
use tree::IteratorNew;

///
/// An Iterator over the ancestors of a `Node`.
///
/// Iterates over the ancestor `Node`s of a given `Node` in the `Tree`.  Each call to `next` will
/// return an immutable reference to the next `Node` up the `Tree`.
///
pub struct Ancestors<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
}

impl<'a, T> IteratorNew<'a, T, Ancestors<'a, T>> for Ancestors<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> Ancestors<'a, T> {
        Ancestors {
            tree: tree,
            node_id: Some(node_id),
        }
    }
}

impl<'a, T> Iterator for Ancestors<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(current_id) = self.node_id.clone() {
            if let Some(parent_id) = self.tree.get_unsafe(&current_id).parent() {
                let parent = self.tree.get_unsafe(&parent_id);
                self.node_id = Some(parent_id.clone());
                return Some(parent);
            } else {
                self.node_id = None;
            }
        }
        None
    }
}

///
/// An Iterator over the ancestors of a `Node`.
///
/// Iterates over `NodeId`s instead of over the `Node`s themselves.
///
pub struct AncestorIds<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
}

impl<'a, T> IteratorNew<'a, T, AncestorIds<'a, T>> for AncestorIds<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> AncestorIds<'a, T> {
        AncestorIds {
            tree: tree,
            node_id: Some(node_id),
        }
    }
}

impl<'a, T> Iterator for AncestorIds<'a, T> {
    type Item = &'a NodeId;

    fn next(&mut self) -> Option<&'a NodeId> {
        if let Some(current_id) = self.node_id.clone() {
            if let Some(parent_id) = self.tree.get_unsafe(&current_id).parent() {
                self.node_id = Some(parent_id.clone());
                return Some(parent_id);
            } else {
                self.node_id = None;
            }
        }
        None
    }
}

///
/// An Iterator over the children of a `Node`.
///
/// Iterates over the child `Node`s of a given `Node` in the `Tree`.  Each call to `next` will
/// return an immutable reference to the next child `Node`.
///
pub struct Children<'a, T: 'a> {
    tree: &'a Tree<T>,
    child_ids: Iter<'a, NodeId>,
}

impl<'a, T> IteratorNew<'a, T, Children<'a, T>> for Children<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> Children<'a, T> {
        Children {
            tree: tree,
            child_ids: tree.get_unsafe(&node_id).children().as_slice().iter(),
        }
    }
}

impl<'a, T> Iterator for Children<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(ref next_child_id) = self.child_ids.next() {
            return Some(self.tree.get_unsafe(next_child_id));
        }
        None
    }
}

///
/// An Iterator over the children of a `Node`.
///
/// Iterates over `NodeId`s instead of over the `Node`s themselves.
///
pub struct ChildrenIds<'a> {
    child_ids: Iter<'a, NodeId>,
}

impl<'a, T> IteratorNew<'a, T, ChildrenIds<'a>> for ChildrenIds<'a> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> ChildrenIds<'a> {
        ChildrenIds { child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() }
    }
}

impl<'a> Iterator for ChildrenIds<'a> {
    type Item = &'a NodeId;

    fn next(&mut self) -> Option<&'a NodeId> {
        self.child_ids.next()
    }
}

///
/// An Iterator over the sub-tree relative to a given `Node`.
///
/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`.  Each call to
/// `next` will return an immutable reference to the next `Node` in Pre-Order Traversal order.
///
pub struct PreOrderTraversal<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
    future_data: Vec<&'a NodeId>,
}

impl<'a, T> IteratorNew<'a, T, PreOrderTraversal<'a, T>> for PreOrderTraversal<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> PreOrderTraversal<T> {
        PreOrderTraversal {
            tree: tree,
            node_id: Some(node_id),
            // over allocating, but all at once instead of re-sizing and re-allocating as we go
            future_data: Vec::with_capacity(tree.nodes.capacity()),
        }
    }
}

impl<'a, T> Iterator for PreOrderTraversal<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(node_id) = self.node_id.clone() {

            let node = self.tree.get_unsafe(&node_id);

            if !node.children().is_empty() {
                let mut children_ids = node.children().iter();

                // take the first child and set it as the next one to be processed
                self.node_id = children_ids.next().cloned();

                // reverse it because we will pop to get the next one later.
                let mut new_ids: Vec<&NodeId> = children_ids.rev().collect();

                self.future_data.append(&mut new_ids);
            } else {
                self.node_id = self.future_data.pop().cloned();
            }

            return Some(node);
        }
        None
    }
}

///
/// An Iterator over the sub-tree relative to a given `Node`.
///
/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`.  Each call to
/// `next` will return an immutable reference to the next `Node` in Post-Order Traversal order.
///
pub struct PostOrderTraversal<'a, T: 'a> {
    tree: &'a Tree<T>,
    index: usize,
    data: Vec<NodeId>,
}

impl<'a, T> PostOrderTraversal<'a, T> {
    fn process_nodes(&mut self, starting_id: NodeId) {
        let node = self.tree.get_unsafe(&starting_id);

        for child_id in node.children() {
            self.process_nodes(child_id.clone());
        }

        self.data.push(starting_id);
    }
}

impl<'a, T> IteratorNew<'a, T, PostOrderTraversal<'a, T>> for PostOrderTraversal<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> PostOrderTraversal<T> {
        let mut traversal = PostOrderTraversal {
            tree: tree,
            index: 0,
            // over allocating, but all at once instead of re-sizing and re-allocating as we go
            data: Vec::with_capacity(tree.nodes.capacity()),
        };

        traversal.process_nodes(node_id);
        traversal
    }
}

impl<'a, T> Iterator for PostOrderTraversal<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {

        let id = self.data.get(self.index);
        self.index += 1;

        if let Some(node_id) = id {
            return Some(self.tree.get_unsafe(node_id));
        }

        None
    }
}

#[cfg(test)]
mod tests {

    use Tree;
    use Node;
    use InsertBehavior::*;

    #[test]
    fn test_ancestors() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let ancestors = tree.ancestors(&root_id).unwrap();
        assert_eq!(ancestors.count(), 0);

        let data = [0];
        for (index, node) in tree.ancestors(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node) in tree.ancestors(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node) in tree.ancestors(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }

    #[test]
    fn test_ancestor_ids() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let ancestor_ids = tree.ancestor_ids(&root_id).unwrap();
        assert_eq!(ancestor_ids.count(), 0);

        let data = [0];
        for (index, node_id) in tree.ancestor_ids(&node_1).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node_id) in tree.ancestor_ids(&node_2).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node_id) in tree.ancestor_ids(&node_3).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }
    }

    #[test]
    fn test_children() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [1];
        for (index, node) in tree.children(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2, 3];
        for (index, node) in tree.children(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let children = tree.children(&node_2).unwrap();
        assert_eq!(children.count(), 0);

        let children = tree.children(&node_3).unwrap();
        assert_eq!(children.count(), 0);
    }

    #[test]
    fn test_children_ids() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [1];
        for (index, node_id) in tree.children_ids(&root_id).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [2, 3];
        for (index, node_id) in tree.children_ids(&node_1).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let children_ids = tree.children_ids(&node_2).unwrap();
        assert_eq!(children_ids.count(), 0);

        let children_ids = tree.children_ids(&node_3).unwrap();
        assert_eq!(children_ids.count(), 0);
    }

    #[test]
    fn test_pre_order_traversal() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [0, 1, 2, 3];
        for (index, node) in tree.traverse_pre_order(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 2, 3];
        for (index, node) in tree.traverse_pre_order(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2];
        for (index, node) in tree.traverse_pre_order(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [3];
        for (index, node) in tree.traverse_pre_order(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }

    #[test]
    fn test_post_order_traversal() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [2, 3, 1, 0];
        for (index, node) in tree.traverse_post_order(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2, 3, 1];
        for (index, node) in tree.traverse_post_order(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2];
        for (index, node) in tree.traverse_post_order(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [3];
        for (index, node) in tree.traverse_post_order(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }
}
<commit_msg>get rid of extra usize and bounds checking<commit_after>use std::slice::Iter;
use std::vec::IntoIter;

use Tree;
use Node;
use NodeId;
use tree::IteratorNew;

///
/// An Iterator over the ancestors of a `Node`.
///
/// Iterates over the ancestor `Node`s of a given `Node` in the `Tree`.  Each call to `next` will
/// return an immutable reference to the next `Node` up the `Tree`.
///
pub struct Ancestors<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
}

impl<'a, T> IteratorNew<'a, T, Ancestors<'a, T>> for Ancestors<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> Ancestors<'a, T> {
        Ancestors {
            tree: tree,
            node_id: Some(node_id),
        }
    }
}

impl<'a, T> Iterator for Ancestors<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(current_id) = self.node_id.clone() {
            if let Some(parent_id) = self.tree.get_unsafe(&current_id).parent() {
                let parent = self.tree.get_unsafe(&parent_id);
                self.node_id = Some(parent_id.clone());
                return Some(parent);
            } else {
                self.node_id = None;
            }
        }
        None
    }
}

///
/// An Iterator over the ancestors of a `Node`.
///
/// Iterates over `NodeId`s instead of over the `Node`s themselves.
///
pub struct AncestorIds<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
}

impl<'a, T> IteratorNew<'a, T, AncestorIds<'a, T>> for AncestorIds<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> AncestorIds<'a, T> {
        AncestorIds {
            tree: tree,
            node_id: Some(node_id),
        }
    }
}

impl<'a, T> Iterator for AncestorIds<'a, T> {
    type Item = &'a NodeId;

    fn next(&mut self) -> Option<&'a NodeId> {
        if let Some(current_id) = self.node_id.clone() {
            if let Some(parent_id) = self.tree.get_unsafe(&current_id).parent() {
                self.node_id = Some(parent_id.clone());
                return Some(parent_id);
            } else {
                self.node_id = None;
            }
        }
        None
    }
}

///
/// An Iterator over the children of a `Node`.
///
/// Iterates over the child `Node`s of a given `Node` in the `Tree`.  Each call to `next` will
/// return an immutable reference to the next child `Node`.
///
pub struct Children<'a, T: 'a> {
    tree: &'a Tree<T>,
    child_ids: Iter<'a, NodeId>,
}

impl<'a, T> IteratorNew<'a, T, Children<'a, T>> for Children<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> Children<'a, T> {
        Children {
            tree: tree,
            child_ids: tree.get_unsafe(&node_id).children().as_slice().iter(),
        }
    }
}

impl<'a, T> Iterator for Children<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(ref next_child_id) = self.child_ids.next() {
            return Some(self.tree.get_unsafe(next_child_id));
        }
        None
    }
}

///
/// An Iterator over the children of a `Node`.
///
/// Iterates over `NodeId`s instead of over the `Node`s themselves.
///
pub struct ChildrenIds<'a> {
    child_ids: Iter<'a, NodeId>,
}

impl<'a, T> IteratorNew<'a, T, ChildrenIds<'a>> for ChildrenIds<'a> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> ChildrenIds<'a> {
        ChildrenIds { child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() }
    }
}

impl<'a> Iterator for ChildrenIds<'a> {
    type Item = &'a NodeId;

    fn next(&mut self) -> Option<&'a NodeId> {
        self.child_ids.next()
    }
}

///
/// An Iterator over the sub-tree relative to a given `Node`.
///
/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`.  Each call to
/// `next` will return an immutable reference to the next `Node` in Pre-Order Traversal order.
///
pub struct PreOrderTraversal<'a, T: 'a> {
    tree: &'a Tree<T>,
    node_id: Option<NodeId>,
    future_data: Vec<&'a NodeId>,
}

impl<'a, T> IteratorNew<'a, T, PreOrderTraversal<'a, T>> for PreOrderTraversal<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> PreOrderTraversal<T> {
        PreOrderTraversal {
            tree: tree,
            node_id: Some(node_id),
            // over allocating, but all at once instead of re-sizing and re-allocating as we go
            future_data: Vec::with_capacity(tree.nodes.capacity()),
        }
    }
}

impl<'a, T> Iterator for PreOrderTraversal<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        if let Some(node_id) = self.node_id.clone() {

            let node = self.tree.get_unsafe(&node_id);

            if !node.children().is_empty() {
                let mut children_ids = node.children().iter();

                // take the first child and set it as the next one to be processed
                self.node_id = children_ids.next().cloned();

                // reverse it because we will pop to get the next one later.
                let mut new_ids: Vec<&NodeId> = children_ids.rev().collect();

                self.future_data.append(&mut new_ids);
            } else {
                self.node_id = self.future_data.pop().cloned();
            }

            return Some(node);
        }
        None
    }
}

///
/// An Iterator over the sub-tree relative to a given `Node`.
///
/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`.  Each call to
/// `next` will return an immutable reference to the next `Node` in Post-Order Traversal order.
///
pub struct PostOrderTraversal<'a, T: 'a> {
    tree: &'a Tree<T>,
    ids: IntoIter<NodeId>,
}

impl<'a, T> PostOrderTraversal<'a, T> {
    fn process_nodes(starting_id: NodeId, tree: &Tree<T>, ids: &mut Vec<NodeId>) {
        let node = tree.get_unsafe(&starting_id);

        for child_id in node.children() {
            PostOrderTraversal::process_nodes(child_id.clone(), tree, ids);
        }

        ids.push(starting_id);
    }
}

impl<'a, T> IteratorNew<'a, T, PostOrderTraversal<'a, T>> for PostOrderTraversal<'a, T> {
    fn new(tree: &'a Tree<T>, node_id: NodeId) -> PostOrderTraversal<T> {

        // over allocating, but all at once instead of re-sizing and re-allocating as we go
        let mut ids = Vec::with_capacity(tree.nodes.capacity());

        PostOrderTraversal::process_nodes(node_id, tree, &mut ids);

        PostOrderTraversal {
            tree: tree,
            ids: ids.into_iter(),
        }
    }
}

impl<'a, T> Iterator for PostOrderTraversal<'a, T> {
    type Item = &'a Node<T>;

    fn next(&mut self) -> Option<&'a Node<T>> {
        let id = self.ids.next();

        if let Some(ref node_id) = id {
            return Some(self.tree.get_unsafe(node_id));
        }

        None
    }
}

#[cfg(test)]
mod tests {

    use Tree;
    use Node;
    use InsertBehavior::*;

    #[test]
    fn test_ancestors() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let ancestors = tree.ancestors(&root_id).unwrap();
        assert_eq!(ancestors.count(), 0);

        let data = [0];
        for (index, node) in tree.ancestors(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node) in tree.ancestors(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node) in tree.ancestors(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }

    #[test]
    fn test_ancestor_ids() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let ancestor_ids = tree.ancestor_ids(&root_id).unwrap();
        assert_eq!(ancestor_ids.count(), 0);

        let data = [0];
        for (index, node_id) in tree.ancestor_ids(&node_1).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node_id) in tree.ancestor_ids(&node_2).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [1, 0];
        for (index, node_id) in tree.ancestor_ids(&node_3).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }
    }

    #[test]
    fn test_children() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [1];
        for (index, node) in tree.children(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2, 3];
        for (index, node) in tree.children(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let children = tree.children(&node_2).unwrap();
        assert_eq!(children.count(), 0);

        let children = tree.children(&node_3).unwrap();
        assert_eq!(children.count(), 0);
    }

    #[test]
    fn test_children_ids() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [1];
        for (index, node_id) in tree.children_ids(&root_id).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let data = [2, 3];
        for (index, node_id) in tree.children_ids(&node_1).unwrap().enumerate() {
            assert_eq!(tree.get(node_id).unwrap().data(), &data[index]);
        }

        let children_ids = tree.children_ids(&node_2).unwrap();
        assert_eq!(children_ids.count(), 0);

        let children_ids = tree.children_ids(&node_3).unwrap();
        assert_eq!(children_ids.count(), 0);
    }

    #[test]
    fn test_pre_order_traversal() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [0, 1, 2, 3];
        for (index, node) in tree.traverse_pre_order(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [1, 2, 3];
        for (index, node) in tree.traverse_pre_order(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2];
        for (index, node) in tree.traverse_pre_order(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [3];
        for (index, node) in tree.traverse_pre_order(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }

    #[test]
    fn test_post_order_traversal() {
        let mut tree = Tree::new();

        let root_id = tree.insert(Node::new(0), AsRoot).unwrap();
        let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap();
        let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap();
        let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap();

        let data = [2, 3, 1, 0];
        for (index, node) in tree.traverse_post_order(&root_id).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2, 3, 1];
        for (index, node) in tree.traverse_post_order(&node_1).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [2];
        for (index, node) in tree.traverse_post_order(&node_2).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }

        let data = [3];
        for (index, node) in tree.traverse_post_order(&node_3).unwrap().enumerate() {
            assert_eq!(node.data(), &data[index]);
        }
    }
}
<|endoftext|>


<commit_before>extern crate identicon;
extern crate openssl;
extern crate test;

use openssl::crypto::hash::{Hasher, HashType};
use test::Bencher;

use identicon::Identicon;

#[bench]
fn generate(x: &mut Bencher) {
    let source = String::from_str("42");
    let input = source.as_bytes();

    x.iter(|| {
        let mut hash = Hasher::new(HashType::MD5);
        hash.update(input);
        let bytes = hash.finalize();
        Identicon::new(&bytes[0..]).image();
    });
}
<commit_msg>Use hash function to consume all input at once.<commit_after>extern crate identicon;
extern crate openssl;
extern crate test;

use openssl::crypto::hash::{hash, Type};
use test::Bencher;

use identicon::Identicon;

#[bench]
fn generate(x: &mut Bencher) {
    let source = String::from_str("42");
    let input = source.as_bytes();

    x.iter(|| {
        let bytes = hash(Type::MD5, input);
        Identicon::new(&bytes[0..]).image();
    });
}
<|endoftext|>


<commit_before>//! Basic digital signal processing (DSP) operations
//!
//! Digital signal processing based on real or complex vectors in time or frequency domain.
//! Vectors are expected to typically have a size which is at least in the order
//! of magnitude of a couple of thousand elements. This crate tries to balance between a clear
//! API and performance in terms of processing speed.
//!
//! Take this example:
//!
//! ```
//! # extern crate num_complex;
//! # extern crate basic_dsp_vector;
//! # use basic_dsp_vector::*;
//! # fn main() {
//! let mut vector1 = vec!(1.0, 2.0).to_real_time_vec();
//! let vector2 = vec!(10.0, 11.0).to_real_time_vec();
//! vector1.add(&vector2).expect("Ignoring error handling in examples");
//! # }
//!
//! ```
//! If `vector2` would be a complex or frequency vector then this won't compile. The type mismatch
//! indicates that a conversation is missing and that this might be a programming mistake. This lib uses
//! the Rust type system to catch such errors.
//!
//! DSP algorithms are often executed in loops. If you work with large vectors you typically try to avoid
//! allocating buffers in every iteration. Preallocating buffers is a common practice to safe a little time
//! with every iteration later on, but also to avoid heap fragmentation. At the same time it's a tedious task
//! to calculate the right buffer sizes for all operations. As an attempt to provide a more convenient solution
//! buffer types exist which don't preallocate, but store temporary memory segments so that they can be reused in the
//! next iteration. Here is an example:
//!
//! ```
//! # use std::f32;
//! # use basic_dsp_vector::*;
//! let vector = vec!(1.0, 0.0, -0.5, 0.8660254, -0.5, -0.8660254).to_complex_time_vec();
//! let mut buffer = SingleBuffer::new();
//! let _ = vector.fft(&mut buffer);
//! ```
//!
//! The vector types don't distinguish between the shapes 1xN or Nx1. This is a difference to other
//! conventions such as in MATLAB or GNU Octave.
//! The reason for this decision is that most operations are only defined if the shape of the
//! vector matches. So it appears to be more practical and clearer to implement the few operations
//! where the arguments can be of different shapes as seperate methods. The methods `mul` and `dot_product`
//! are one example for this.
//!
//! The trait definitions in this lib can look complex and might be overwhelming at the beginning.
//! There is a wide range of DSP vectors, e.g. a slice can be DSP vector, a boxed array can be a DSP vector,
//! a standard vector can be a DSP vector and so on. This lib tries to work with all of that and tries
//! to allow all those different DSP vector types to work together. The price for this flexibility is a more complex
//! trait definition. As a mental model, this is what the traits are specifiying:
//! Whenever you have a complex vector in time domain, it's binary operations will work with all other
//! complex vectors in time domain, but not with real valued vectors or frequency domain vectors.
//! And the type `GenDspVec` serves as wild card at compile time since it defers all checks to run time.

#[cfg(any(feature = "doc", feature="use_sse", feature="use_avx"))]
extern crate simd;
#[cfg(any(feature = "doc", feature="use_gpu"))]
extern crate ocl;
#[cfg(feature="std")]
extern crate num_cpus;
#[cfg(feature="std")]
extern crate crossbeam;
extern crate num_traits;
extern crate num_complex;
extern crate rustfft;
#[cfg(any(feature = "doc", feature="use_gpu"))]
extern crate clfft;
extern crate arrayvec;
#[macro_use]
mod simd_extensions;
mod vector_types;
mod multicore_support;
pub mod window_functions;
pub mod conv_types;
pub use vector_types::*;
pub use multicore_support::MultiCoreSettings;
mod gpu_support;
use std::mem;
mod inline_vector;
use numbers::*;
use std::ops::Range;

pub mod numbers {
    //! Traits from the `num` crate which are used inside `basic_dsp` and extensions to those traits.
    pub use num_traits::Float;
    pub use num_traits::One;
    pub use num_complex::Complex;
    pub use num_traits::Num;
    use std::fmt::Debug;
    use rustfft;
    use num_traits;
    use simd_extensions;
    use simd_extensions::*;
    use gpu_support::{Gpu32, Gpu64, GpuRegTrait, GpuFloat};
    #[cfg(any(feature="use_sse", feature="use_avx", feature="use_avx512"))]
    use simd;

    /// A trait for a numeric value which at least supports a subset of the operations defined in this crate.
    /// Can be an integer or a floating point number. In order to have support for all operations in this crate
    /// a must implement the `RealNumber`.
    pub trait DspNumber
        : Num + Copy + Clone + Send + Sync + ToSimd + Debug + num_traits::Signed + num_traits::FromPrimitive + rustfft::FFTnum + 'static
    {
    }
    impl<T> DspNumber for T
        where T: Num + Copy + Clone + Send + Sync + ToSimd + Debug + num_traits::Signed + num_traits::FromPrimitive + rustfft::FFTnum + 'static
    {
    }

    /// Associates a number type with a SIMD register type.
    pub trait ToSimd: Sized + Sync + Send {
        /// Type for the SIMD register on the CPU.
        type RegFallback: SimdGeneric<Self>;
        type RegSse : SimdGeneric<Self>;
        type RegAvx : SimdGeneric<Self>;
        type RegAvx512 : SimdGeneric<Self>;
        /// Type for the SIMD register on the GPU. Defaults to an arbitrary type if GPU support is not
        /// compiled in.
        type GpuReg: GpuRegTrait;
    }

    impl ToSimd for f32 {
        type RegFallback = simd_extensions::fallback::f32x4;

        #[cfg(feature="use_sse")]
        type RegSse = simd::f32x4;
        #[cfg(not(feature="use_sse"))]
        type RegSse = simd_extensions::fallback::f32x4;

        #[cfg(feature="use_avx")]
        type RegAvx = simd::x86::avx::f32x8;
        #[cfg(not(feature="use_avx"))]
        type RegAvx = simd::f32x4;

        #[cfg(feature="use_avx512")]
        type RegAvx512 = stdsimd::simd::f32x16; // Type is missing in SIMD
        #[cfg(not(feature="use_avx512"))]
        type RegAvx512 = simd_extensions::fallback::f32x4;

        type GpuReg = Gpu32;
    }

    impl ToSimd for f64 {
        type RegFallback = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_sse")]
        type RegSse = simd::x86::sse2::f64x2;
        #[cfg(not(feature="use_sse"))]
        type RegSse = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_avx")]
        type RegAvx = simd::x86::avx::f64x4;
        #[cfg(not(feature="use_avx"))]
        type RegAvx = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_avx512")]
        type RegAvx512 = stdsimd::simd::f64x8; // Type is missing in SIMD
        #[cfg(not(feature="use_avx512"))]
        type RegAvx512 = simd_extensions::fallback::f64x2;

        type GpuReg = Gpu64;
    }

    /// A real floating pointer number intended to abstract over `f32` and `f64`.
    pub trait RealNumber: Float + DspNumber + GpuFloat + num_traits::FloatConst {}
    impl<T> RealNumber for T where T: Float + DspNumber + GpuFloat + num_traits::FloatConst {}

    /// This trait is necessary so that we can define zero for types outside this crate.
    /// It calls the `num_traits::Zero` trait where possible.
    pub trait Zero {
        fn zero() -> Self;
    }

    impl<T> Zero for T
        where T: DspNumber
    {
        fn zero() -> Self {
            <Self as num_traits::Zero>::zero()
        }
    }

    impl<T> Zero for Complex<T>
        where T: DspNumber
    {
        fn zero() -> Self {
            <Self as num_traits::Zero>::zero()
        }
    }
}

// Returns a complex slice from a real slice
fn array_to_complex<T>(array: &[T]) -> &[Complex<T>] {
    unsafe {
        let len = array.len();
        if len % 2 != 0 {
            panic!("Argument must have an even length");
        }
        let trans: &[Complex<T>] = mem::transmute(array);
        &trans[0..len / 2]
    }
}

// Returns a complex slice from a real slice
fn array_to_complex_mut<T>(array: &mut [T]) -> &mut [Complex<T>] {
    unsafe {
        let len = array.len();
        if len % 2 != 0 {
            panic!("Argument must have an even length");
        }
        let trans: &mut [Complex<T>] = mem::transmute(array);
        &mut trans[0..len / 2]
    }
}

/// Copies memory inside a slice
fn memcpy<T: Copy>(data: &mut [T], from: Range<usize>, to: usize) {
    use std::ptr::copy;
    assert!(from.start <= from.end);
    assert!(from.end <= data.len());
    assert!(to <= data.len() - (from.end - from.start));
    unsafe {
        let ptr = data.as_mut_ptr();
        copy(ptr.offset(from.start as isize),
             ptr.offset(to as isize),
             from.end - from.start)
    }
}

// Zeros a range within the slice
fn memzero<T: Copy>(data: &mut [T], range: Range<usize>) {
    use std::ptr::write_bytes;
    assert!(range.start <= range.end);
    assert!(range.end <= data.len());
    unsafe {
        let ptr = data.as_mut_ptr();
        write_bytes(ptr.offset(range.start as isize), 0, range.end - range.start);
    }
}

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

    #[test]
    fn to_simd_test() {
        // This is more a check for syntax. So if it compiles
        // then the test already passes. The assert is then only
        // a sanity check.
        let reg = <f32 as ToSimd>::RegFallback::splat(1.0);
        let sum = reg.sum_real();
        assert!(sum > 0.0);
    }
}
<commit_msg>Fixed build error<commit_after>//! Basic digital signal processing (DSP) operations
//!
//! Digital signal processing based on real or complex vectors in time or frequency domain.
//! Vectors are expected to typically have a size which is at least in the order
//! of magnitude of a couple of thousand elements. This crate tries to balance between a clear
//! API and performance in terms of processing speed.
//!
//! Take this example:
//!
//! ```
//! # extern crate num_complex;
//! # extern crate basic_dsp_vector;
//! # use basic_dsp_vector::*;
//! # fn main() {
//! let mut vector1 = vec!(1.0, 2.0).to_real_time_vec();
//! let vector2 = vec!(10.0, 11.0).to_real_time_vec();
//! vector1.add(&vector2).expect("Ignoring error handling in examples");
//! # }
//!
//! ```
//! If `vector2` would be a complex or frequency vector then this won't compile. The type mismatch
//! indicates that a conversation is missing and that this might be a programming mistake. This lib uses
//! the Rust type system to catch such errors.
//!
//! DSP algorithms are often executed in loops. If you work with large vectors you typically try to avoid
//! allocating buffers in every iteration. Preallocating buffers is a common practice to safe a little time
//! with every iteration later on, but also to avoid heap fragmentation. At the same time it's a tedious task
//! to calculate the right buffer sizes for all operations. As an attempt to provide a more convenient solution
//! buffer types exist which don't preallocate, but store temporary memory segments so that they can be reused in the
//! next iteration. Here is an example:
//!
//! ```
//! # use std::f32;
//! # use basic_dsp_vector::*;
//! let vector = vec!(1.0, 0.0, -0.5, 0.8660254, -0.5, -0.8660254).to_complex_time_vec();
//! let mut buffer = SingleBuffer::new();
//! let _ = vector.fft(&mut buffer);
//! ```
//!
//! The vector types don't distinguish between the shapes 1xN or Nx1. This is a difference to other
//! conventions such as in MATLAB or GNU Octave.
//! The reason for this decision is that most operations are only defined if the shape of the
//! vector matches. So it appears to be more practical and clearer to implement the few operations
//! where the arguments can be of different shapes as seperate methods. The methods `mul` and `dot_product`
//! are one example for this.
//!
//! The trait definitions in this lib can look complex and might be overwhelming at the beginning.
//! There is a wide range of DSP vectors, e.g. a slice can be DSP vector, a boxed array can be a DSP vector,
//! a standard vector can be a DSP vector and so on. This lib tries to work with all of that and tries
//! to allow all those different DSP vector types to work together. The price for this flexibility is a more complex
//! trait definition. As a mental model, this is what the traits are specifiying:
//! Whenever you have a complex vector in time domain, it's binary operations will work with all other
//! complex vectors in time domain, but not with real valued vectors or frequency domain vectors.
//! And the type `GenDspVec` serves as wild card at compile time since it defers all checks to run time.

#[cfg(any(feature = "doc", feature="use_sse", feature="use_avx"))]
extern crate simd;
#[cfg(any(feature = "doc", feature="use_gpu"))]
extern crate ocl;
#[cfg(feature="std")]
extern crate num_cpus;
#[cfg(feature="std")]
extern crate crossbeam;
extern crate num_traits;
extern crate num_complex;
extern crate rustfft;
#[cfg(any(feature = "doc", feature="use_gpu"))]
extern crate clfft;
extern crate arrayvec;
#[macro_use]
mod simd_extensions;
mod vector_types;
mod multicore_support;
pub mod window_functions;
pub mod conv_types;
pub use vector_types::*;
pub use multicore_support::MultiCoreSettings;
mod gpu_support;
use std::mem;
mod inline_vector;
use numbers::*;
use std::ops::Range;

pub mod numbers {
    //! Traits from the `num` crate which are used inside `basic_dsp` and extensions to those traits.
    pub use num_traits::Float;
    pub use num_traits::One;
    pub use num_complex::Complex;
    pub use num_traits::Num;
    use std::fmt::Debug;
    use rustfft;
    use num_traits;
    use simd_extensions;
    use simd_extensions::*;
    use gpu_support::{Gpu32, Gpu64, GpuRegTrait, GpuFloat};
    #[cfg(any(feature="use_sse", feature="use_avx", feature="use_avx512"))]
    use simd;

    /// A trait for a numeric value which at least supports a subset of the operations defined in this crate.
    /// Can be an integer or a floating point number. In order to have support for all operations in this crate
    /// a must implement the `RealNumber`.
    pub trait DspNumber
        : Num + Copy + Clone + Send + Sync + ToSimd + Debug + num_traits::Signed + num_traits::FromPrimitive + rustfft::FFTnum + 'static
    {
    }
    impl<T> DspNumber for T
        where T: Num + Copy + Clone + Send + Sync + ToSimd + Debug + num_traits::Signed + num_traits::FromPrimitive + rustfft::FFTnum + 'static
    {
    }

    /// Associates a number type with a SIMD register type.
    pub trait ToSimd: Sized + Sync + Send {
        /// Type for the SIMD register on the CPU.
        type RegFallback: SimdGeneric<Self>;
        type RegSse : SimdGeneric<Self>;
        type RegAvx : SimdGeneric<Self>;
        type RegAvx512 : SimdGeneric<Self>;
        /// Type for the SIMD register on the GPU. Defaults to an arbitrary type if GPU support is not
        /// compiled in.
        type GpuReg: GpuRegTrait;
    }

    impl ToSimd for f32 {
        type RegFallback = simd_extensions::fallback::f32x4;

        #[cfg(feature="use_sse")]
        type RegSse = simd::f32x4;
        #[cfg(not(feature="use_sse"))]
        type RegSse = simd_extensions::fallback::f32x4;

        #[cfg(feature="use_avx")]
        type RegAvx = simd::x86::avx::f32x8;
        #[cfg(not(feature="use_avx"))]
        type RegAvx = simd_extensions::fallback::f32x4;

        #[cfg(feature="use_avx512")]
        type RegAvx512 = stdsimd::simd::f32x16; // Type is missing in SIMD
        #[cfg(not(feature="use_avx512"))]
        type RegAvx512 = simd_extensions::fallback::f32x4;

        type GpuReg = Gpu32;
    }

    impl ToSimd for f64 {
        type RegFallback = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_sse")]
        type RegSse = simd::x86::sse2::f64x2;
        #[cfg(not(feature="use_sse"))]
        type RegSse = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_avx")]
        type RegAvx = simd::x86::avx::f64x4;
        #[cfg(not(feature="use_avx"))]
        type RegAvx = simd_extensions::fallback::f64x2;

        #[cfg(feature="use_avx512")]
        type RegAvx512 = stdsimd::simd::f64x8; // Type is missing in SIMD
        #[cfg(not(feature="use_avx512"))]
        type RegAvx512 = simd_extensions::fallback::f64x2;

        type GpuReg = Gpu64;
    }

    /// A real floating pointer number intended to abstract over `f32` and `f64`.
    pub trait RealNumber: Float + DspNumber + GpuFloat + num_traits::FloatConst {}
    impl<T> RealNumber for T where T: Float + DspNumber + GpuFloat + num_traits::FloatConst {}

    /// This trait is necessary so that we can define zero for types outside this crate.
    /// It calls the `num_traits::Zero` trait where possible.
    pub trait Zero {
        fn zero() -> Self;
    }

    impl<T> Zero for T
        where T: DspNumber
    {
        fn zero() -> Self {
            <Self as num_traits::Zero>::zero()
        }
    }

    impl<T> Zero for Complex<T>
        where T: DspNumber
    {
        fn zero() -> Self {
            <Self as num_traits::Zero>::zero()
        }
    }
}

// Returns a complex slice from a real slice
fn array_to_complex<T>(array: &[T]) -> &[Complex<T>] {
    unsafe {
        let len = array.len();
        if len % 2 != 0 {
            panic!("Argument must have an even length");
        }
        let trans: &[Complex<T>] = mem::transmute(array);
        &trans[0..len / 2]
    }
}

// Returns a complex slice from a real slice
fn array_to_complex_mut<T>(array: &mut [T]) -> &mut [Complex<T>] {
    unsafe {
        let len = array.len();
        if len % 2 != 0 {
            panic!("Argument must have an even length");
        }
        let trans: &mut [Complex<T>] = mem::transmute(array);
        &mut trans[0..len / 2]
    }
}

/// Copies memory inside a slice
fn memcpy<T: Copy>(data: &mut [T], from: Range<usize>, to: usize) {
    use std::ptr::copy;
    assert!(from.start <= from.end);
    assert!(from.end <= data.len());
    assert!(to <= data.len() - (from.end - from.start));
    unsafe {
        let ptr = data.as_mut_ptr();
        copy(ptr.offset(from.start as isize),
             ptr.offset(to as isize),
             from.end - from.start)
    }
}

// Zeros a range within the slice
fn memzero<T: Copy>(data: &mut [T], range: Range<usize>) {
    use std::ptr::write_bytes;
    assert!(range.start <= range.end);
    assert!(range.end <= data.len());
    unsafe {
        let ptr = data.as_mut_ptr();
        write_bytes(ptr.offset(range.start as isize), 0, range.end - range.start);
    }
}

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

    #[test]
    fn to_simd_test() {
        // This is more a check for syntax. So if it compiles
        // then the test already passes. The assert is then only
        // a sanity check.
        let reg = <f32 as ToSimd>::RegFallback::splat(1.0);
        let sum = reg.sum_real();
        assert!(sum > 0.0);
    }
}
<|endoftext|>