<commit_before>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().expect("Failed to get filename of path"));
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().expect("Failed to get the current directory").join("libsass")
}

#[cfg(target_os = "linux")]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        panic!("no c++ library found");
    }
}

#[cfg(not(target_os = "linux"))]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else {
        panic!("no c++ library found");
    }
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("Failed to run make/gmake. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run cc. Do you have it installed?")
        .success()
    };
    _compile(libprobe);
}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("Failed to run devenv. Do you have it installed?");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("where")
        .args(&["msbuild.exe"])
        .output()
        .expect("Failed to run where: Could not search for msbuild.exe on path.");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("Failed to run msbuild. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    if !Path::new("libsass/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init"])
            .status();
    }

    // If it still doesn't exist, stop there
    if !Path::new("libsass/.git").exists() {
        return;
    }

    compile();
}
<commit_msg>Revert "Conditionally call submodule update"<commit_after>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().expect("Failed to get filename of path"));
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().expect("Failed to get the current directory").join("libsass")
}

#[cfg(target_os = "linux")]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        panic!("no c++ library found");
    }
}

#[cfg(not(target_os = "linux"))]
fn _compile(libprobe: fn(&str) -> bool) {
    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    } else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else {
        panic!("no c++ library found");
    }
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("Failed to run make/gmake. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("Failed to run cc. Do you have it installed?")
        .success()
    };
    _compile(libprobe);
}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment"));
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("Failed to run devenv. Do you have it installed?");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("where")
        .args(&["msbuild.exe"])
        .output()
        .expect("Failed to run where: Could not search for msbuild.exe on path.");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("Failed to run msbuild. Do you have it installed?");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    compile();
}
<|endoftext|>


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

use core::convert::Infallible;
use std::time::Duration;

use embedded_hal::digital::blocking::{
    InputPin as InputPinHal, StatefulOutputPin as StatefulOutputPinHal,
    ToggleableOutputPin as ToggleableOutputPinHal,
};
use embedded_hal::pwm::blocking::Pwm as PwmHal;

use super::{InputPin, IoPin, OutputPin, Pin};
use crate::gpio::Mode;

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for Pin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for InputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for IoPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for OutputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for IoPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for OutputPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for IoPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for OutputPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for OutputPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::disable(self, &channel);
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::enable(self, &channel);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        PwmHal::get_period(self).unwrap_or_default()
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
        PwmHal::get_duty(self, &channel).unwrap_or_default()
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        PwmHal::get_max_duty(self).unwrap_or(1.0)
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
        let _ = PwmHal::set_duty(self, &channel, duty);
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let _ = PwmHal::set_period(self, period);
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for IoPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::disable(self, &channel);
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::enable(self, &channel);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        PwmHal::get_period(self).unwrap_or_default()
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
        PwmHal::get_duty(self, &channel).unwrap_or_default()
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        PwmHal::get_max_duty(self).unwrap_or(1.0)
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
        let _ = PwmHal::set_duty(self, &channel, duty);
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let _ = PwmHal::set_period(self, period);
    }
}

/// Unproven `IoPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::IoPin<IoPin, IoPin> for IoPin {
    type Error = Infallible;

    /// Tries to convert this pin to input mode.
    ///
    /// If the pin is already in input mode, this method should succeed.
    fn into_input_pin(mut self) -> Result<IoPin, Self::Error> {
        let now_mode = self.mode();
        return if now_mode == Mode::Input {
            Ok(self)
        } else {
            self.set_mode(Mode::Input);
            Ok(self)
        };
    }

    /// Tries to convert this pin to output mode with the given initial state.
    ///
    /// If the pin is already in the requested state, this method should
    /// succeed.
    fn into_output_pin(
        mut self,
        state: embedded_hal_0::digital::v2::PinState,
    ) -> Result<IoPin, Self::Error> {
        let now_mode = self.mode();

        return if now_mode == Mode::Output {
            match state {
                embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
                embedded_hal_0::digital::v2::PinState::High => self.set_high(),
            }
            Ok(self)
        } else {
            self.set_mode(Mode::Output);
            match state {
                embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
                embedded_hal_0::digital::v2::PinState::High => self.set_high(),
            }
            Ok(self)
        };
    }
}
<commit_msg>Refactor code<commit_after>// Copyright (c) 2017-2021 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use core::convert::Infallible;
use std::time::Duration;

use embedded_hal::digital::blocking::{
    InputPin as InputPinHal, StatefulOutputPin as StatefulOutputPinHal,
    ToggleableOutputPin as ToggleableOutputPinHal,
};
use embedded_hal::pwm::blocking::Pwm as PwmHal;

use super::{InputPin, IoPin, OutputPin, Pin};
use crate::gpio::Mode;

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for Pin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for InputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for IoPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `InputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::InputPin for OutputPin {
    type Error = Infallible;

    fn is_high(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_high(self)
    }

    fn is_low(&self) -> Result<bool, Self::Error> {
        InputPinHal::is_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for IoPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `StatefulOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::StatefulOutputPin for OutputPin {
    fn is_set_high(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_high(self)
    }

    fn is_set_low(&self) -> Result<bool, Self::Error> {
        StatefulOutputPinHal::is_set_low(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for IoPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `ToggleableOutputPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::ToggleableOutputPin for OutputPin {
    type Error = Infallible;

    fn toggle(&mut self) -> Result<(), Self::Error> {
        ToggleableOutputPinHal::toggle(self)
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for OutputPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::disable(self, &channel);
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::enable(self, &channel);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        PwmHal::get_period(self).unwrap_or_default()
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
        PwmHal::get_duty(self, &channel).unwrap_or_default()
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        PwmHal::get_max_duty(self).unwrap_or(1.0)
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
        let _ = PwmHal::set_duty(self, &channel, duty);
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let _ = PwmHal::set_period(self, period);
    }
}

/// Unproven `Pwm` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::Pwm for IoPin {
    type Duty = f64;
    type Channel = ();
    type Time = Duration;

    /// Disables a PWM `channel`.
    fn disable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::disable(self, &channel);
    }

    /// Enables a PWM `channel`.
    fn enable(&mut self, channel: Self::Channel) {
        let _ = PwmHal::enable(self, &channel);
    }

    /// Returns the current PWM period.
    fn get_period(&self) -> Self::Time {
        PwmHal::get_period(self).unwrap_or_default()
    }

    /// Returns the current duty cycle.
    fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
        PwmHal::get_duty(self, &channel).unwrap_or_default()
    }

    /// Returns the maximum duty cycle value.
    fn get_max_duty(&self) -> Self::Duty {
        PwmHal::get_max_duty(self).unwrap_or(1.0)
    }

    /// Sets a new duty cycle.
    fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
        let _ = PwmHal::set_duty(self, &channel, duty);
    }

    /// Sets a new PWM period.
    fn set_period<P>(&mut self, period: P)
    where
        P: Into<Self::Time>,
    {
        let _ = PwmHal::set_period(self, period);
    }
}

/// Unproven `IoPin` trait implementation for `embedded-hal` v0.2.6.
impl embedded_hal_0::digital::v2::IoPin<IoPin, IoPin> for IoPin {
    type Error = Infallible;

    /// Tries to convert this pin to input mode.
    ///
    /// If the pin is already in input mode, this method should succeed.
    fn into_input_pin(mut self) -> Result<IoPin, Self::Error> {
        if self.mode() == Mode::Input {
            Ok(self)
        } else {
            self.set_mode(Mode::Input);
            Ok(self)
        }
    }

    /// Tries to convert this pin to output mode with the given initial state.
    ///
    /// If the pin is already in the requested state, this method should
    /// succeed.
    fn into_output_pin(
        mut self,
        state: embedded_hal_0::digital::v2::PinState,
    ) -> Result<IoPin, Self::Error> {
        if self.mode() == Mode::Output {
            match state {
                embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
                embedded_hal_0::digital::v2::PinState::High => self.set_high(),
            }
            Ok(self)
        } else {
            self.set_mode(Mode::Output);
            match state {
                embedded_hal_0::digital::v2::PinState::Low => self.set_low(),
                embedded_hal_0::digital::v2::PinState::High => self.set_high(),
            }
            Ok(self)
        }
    }
}
<|endoftext|>


<commit_before>//! Tests

use std::thread;
use std::time::Duration;
use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ParserError, ErrorCode};

use ipc::unique_ish_id;
use super::super::channel::*;

const COMPLEX_JSON: &'static str =
    r#"{ "foo": "bar", "baz": 1, "bar": [ "a", "b", "c", 22], "obj":
{ "foo": "bar", "baz": 22.4 } }"#;

const BAD_JSON_DELIMITER: &'static str = r#"{ "foo": "bar" "#;

const SUCCESS_JSON: &'static str = r#"{ "type": "success" }"#;
const VALUE_JSON: &'static str = r#"{ "type": "success", "value": "foo" }"#;
const SUCCESS_WITH_FOO: &'static str =
    r#"{ "type": "success", "foo": "bar" }"#;
const ERR_JSON_FOO: &'static str = r#"{ "type": "error", "reason": "foo" }"#;
const ERR_JSON_WITH_FOO: &'static str =
    r#"{ "type": "error", "reason": "foo", "foo": "bar" }"#;
const ERR_EXPECTING_KEY: &'static str =
    r#"{ "type": "error", "reason": "missing message field", "missing": "foo",
         "expected": "string" }"#;

#[test]
fn u32_coversion() {
    let nums = [0u32, !2, 255, 256, 1024, 2048, 12, 4096, 1, 0xfffffffe,
                0b11111111, 0xffefff, 0x11111111, 0x0101011, 0xffffffff];
    for num in &nums {
        let be_num = num.to_be();
        let le_num = num.to_le();
        assert_eq!(u32_to_bytes(be_num), u32_to_bytes(be_num));
        assert_eq!(u32_from_bytes(u32_to_bytes(le_num)), le_num);
    }
}

#[test]
fn uniquesh_id_is_uniqueish() {
    let mut ids = Vec::with_capacity(15);
    for _ in 0..15 {
        println!("New id: {}", unique_ish_id());
        ids.push(unique_ish_id());
        thread::sleep(Duration::from_millis(50));
    }
    ids.dedup();
    assert!(ids.len() == 15, "unique_ish_id conflict: {:?}", ids);
}

fn packet_stream_from_str(text: &str) -> Vec<u8> {
    let mut turn = Vec::with_capacity(text.len()+4);
    let mut bytes = text.as_bytes();
    assert!(bytes.len() < 255,
            "Tests only work with < 255 char packets!");
    turn.push(0);
    turn.push(0);
    turn.push(0);
    turn.push(bytes.len() as u8);
    turn.extend_from_slice(&mut bytes);
    return turn;
}

#[test]
fn read_packet_bad_json() {
    let packet = packet_stream_from_str(BAD_JSON_DELIMITER);
    match read_packet(&mut &*packet) {
        Ok(json) => panic!("Got some Json somehow: {:?}", json),
        Err(response) => match response {
            ReceiveError::InvalidJson(err) => match err {
                ParserError::SyntaxError(code, start, end) => {
                    assert_eq!(code, ErrorCode::EOFWhileParsingObject);
                    assert_eq!(start, 1);
                    assert_eq!(end, 16);
                },
                other_json @ _ =>
                    panic!("Unexpected json errr: {:?}", other_json)
            },
            other @ _ => panic!("Unexpected err: {:?}", other)
        }
    }
}

#[test]
fn read_packet_json() {
    let packet = packet_stream_from_str(r#"{ "foo": "bar" }"#);
    match read_packet(&mut &*packet) {
        Ok(json) => {
            let desired = Json::Object(json_object! {
                "foo" => "bar"
            });
            assert_eq!(json, desired);
        }
        Err(err) => panic!("Unable to parse Json: {:?}", err)
    }
}

#[test]
fn read_packet_too_short() {
    let mut packet = Vec::new();
    packet.push(0); packet.push(0); packet.push(0);
    packet.push(5); // Len == 5
    packet.extend_from_slice(br#"{ "foo": 1 }"#);
    // Gets to just before close quote of foo

    match read_packet(&mut &*packet) {
        Ok(json) => panic!("Got a json {:?}, read too much?", json),
        Err(response) => match response {
            ReceiveError::InvalidJson(json_err) => match json_err {
                ParserError::SyntaxError(code, start, end) => {
                    assert_eq!(code, ErrorCode::EOFWhileParsingString);
                    assert_eq!(start, 1); assert_eq!(end, 6);
                },
                other_json @ _ => panic!("Wrong json err: {:?}", other_json)
            },
            other @ _ => panic!("Wrong error: {:?}", other)
        }
    }
}

// There is no packet_too_long test because it would result in the server
// waiting on a call to read() and the client probably not sending more data.

#[test]
fn write_packet_integrity() {
    let packet_json = Json::from_str(COMPLEX_JSON).expect("complex_json");
    let mut packet = Vec::new();
    write_packet(&mut packet, &packet_json).expect("Unable to write pakcet");
    // Remove length
    for _ in 0 .. 4 { packet.remove(0); }
    let text = String::from_utf8(packet).expect("Packet had invalid utf8");
    assert_eq!(packet_json, Json::from_str(&text).expect("Couldn't parse text"));
}

#[test]
fn read_write_packet() {
    let packet_json = Json::from_str(COMPLEX_JSON).expect("complex_json");
    let mut packet = Vec::new();
    write_packet(&mut packet, &packet_json).expect("Could not write");
    let read_json = read_packet(&mut &*packet).expect("Could not read");
    assert_eq!(read_json, packet_json);
}

#[test]
fn success_json_is_successful() {
    assert_eq!(success_json(),
               Json::from_str(SUCCESS_JSON).expect("Can't get success Json"));
    assert_eq!(value_json(Json::String("foo".to_string())),
               Json::from_str(VALUE_JSON).expect("Can't get value Json"));
    let json = json_object!{ "foo" => "bar" };
    assert_eq!(success_json_with(json),
               Json::from_str(SUCCESS_WITH_FOO).expect("Can't get foo Json"));
}

#[test]
fn error_json_is_erroneous() {
    assert_eq!(error_json("foo".to_string()),
               Json::from_str(ERR_JSON_FOO).expect("Can't get err Json"));
    assert_eq!(error_expecting_key("foo", "string"),
               Json::from_str(ERR_EXPECTING_KEY).expect("Cant't get err key Json"));
    let mut json = BTreeMap::new();
    json.insert("foo".to_string(), Json::String("bar".to_string()));
    assert_eq!(error_json_with("foo".to_string(), json),
               Json::from_str(ERR_JSON_WITH_FOO).expect("Can't get foo err Json"));
}

<commit_msg>Fix IPC tests<commit_after>//! Tests

use std::thread;
use std::time::Duration;
use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ParserError, ErrorCode};

use ipc::unique_ish_id;
use super::super::channel::*;

const COMPLEX_JSON: &'static str =
    r#"{ "foo": "bar", "baz": 1, "bar": [ "a", "b", "c", 22], "obj":
{ "foo": "bar", "baz": 22.4 } }"#;

const BAD_JSON_DELIMITER: &'static str = r#"{ "foo": "bar" "#;

const SUCCESS_JSON: &'static str = r#"{ "type": "success" }"#;
const VALUE_JSON: &'static str = r#"{ "type": "success", "value": "foo" }"#;
const SUCCESS_WITH_FOO: &'static str =
    r#"{ "type": "success", "foo": "bar" }"#;
const ERR_JSON_FOO: &'static str = r#"{ "type": "error", "reason": "foo" }"#;
const ERR_JSON_WITH_FOO: &'static str =
    r#"{ "type": "error", "reason": "foo", "foo": "bar" }"#;
const ERR_EXPECTING_KEY: &'static str =
    r#"{ "type": "error", "reason": "missing message field", "missing": "foo",
         "expected": "string" }"#;

#[test]
fn uniquesh_id_is_uniqueish() {
    let mut ids = Vec::with_capacity(15);
    for _ in 0..15 {
        println!("New id: {}", unique_ish_id());
        ids.push(unique_ish_id());
        thread::sleep(Duration::from_millis(50));
    }
    ids.dedup();
    assert!(ids.len() == 15, "unique_ish_id conflict: {:?}", ids);
}

fn packet_stream_from_str(text: &str) -> Vec<u8> {
    let mut turn = Vec::with_capacity(text.len()+4);
    let mut bytes = text.as_bytes();
    assert!(bytes.len() < 255,
            "Tests only work with < 255 char packets!");
    turn.push(0);
    turn.push(0);
    turn.push(0);
    turn.push(bytes.len() as u8);
    turn.extend_from_slice(&mut bytes);
    return turn;
}

#[test]
fn read_packet_bad_json() {
    let packet = packet_stream_from_str(BAD_JSON_DELIMITER);
    match read_packet(&mut &*packet) {
        Ok(json) => panic!("Got some Json somehow: {:?}", json),
        Err(response) => match response {
            ReceiveError::InvalidJson(err) => match err {
                ParserError::SyntaxError(code, start, end) => {
                    assert_eq!(code, ErrorCode::EOFWhileParsingObject);
                    assert_eq!(start, 1);
                    assert_eq!(end, 16);
                },
                other_json @ _ =>
                    panic!("Unexpected json errr: {:?}", other_json)
            },
            other @ _ => panic!("Unexpected err: {:?}", other)
        }
    }
}

#[test]
fn read_packet_json() {
    let packet = packet_stream_from_str(r#"{ "foo": "bar" }"#);
    match read_packet(&mut &*packet) {
        Ok(json) => {
            let desired = Json::Object(json_object! {
                "foo" => "bar"
            });
            assert_eq!(json, desired);
        }
        Err(err) => panic!("Unable to parse Json: {:?}", err)
    }
}

#[test]
fn read_packet_too_short() {
    let mut packet = Vec::new();
    packet.push(0); packet.push(0); packet.push(0);
    packet.push(5); // Len == 5
    packet.extend_from_slice(br#"{ "foo": 1 }"#);
    // Gets to just before close quote of foo

    match read_packet(&mut &*packet) {
        Ok(json) => panic!("Got a json {:?}, read too much?", json),
        Err(response) => match response {
            ReceiveError::InvalidJson(json_err) => match json_err {
                ParserError::SyntaxError(code, start, end) => {
                    assert_eq!(code, ErrorCode::EOFWhileParsingString);
                    assert_eq!(start, 1); assert_eq!(end, 6);
                },
                other_json @ _ => panic!("Wrong json err: {:?}", other_json)
            },
            other @ _ => panic!("Wrong error: {:?}", other)
        }
    }
}

// There is no packet_too_long test because it would result in the server
// waiting on a call to read() and the client probably not sending more data.

#[test]
fn write_packet_integrity() {
    let packet_json = Json::from_str(COMPLEX_JSON).expect("complex_json");
    let mut packet = Vec::new();
    write_packet(&mut packet, &packet_json).expect("Unable to write pakcet");
    // Remove length
    for _ in 0 .. 4 { packet.remove(0); }
    let text = String::from_utf8(packet).expect("Packet had invalid utf8");
    assert_eq!(packet_json, Json::from_str(&text).expect("Couldn't parse text"));
}

#[test]
fn read_write_packet() {
    let packet_json = Json::from_str(COMPLEX_JSON).expect("complex_json");
    let mut packet = Vec::new();
    write_packet(&mut packet, &packet_json).expect("Could not write");
    let read_json = read_packet(&mut &*packet).expect("Could not read");
    assert_eq!(read_json, packet_json);
}

#[test]
fn success_json_is_successful() {
    assert_eq!(success_json(),
               Json::from_str(SUCCESS_JSON).expect("Can't get success Json"));
    assert_eq!(value_json(Json::String("foo".to_string())),
               Json::from_str(VALUE_JSON).expect("Can't get value Json"));
    let json = json_object!{ "foo" => "bar" };
    assert_eq!(success_json_with(json),
               Json::from_str(SUCCESS_WITH_FOO).expect("Can't get foo Json"));
}

#[test]
fn error_json_is_erroneous() {
    assert_eq!(error_json("foo".to_string()),
               Json::from_str(ERR_JSON_FOO).expect("Can't get err Json"));
    assert_eq!(error_expecting_key("foo", "string"),
               Json::from_str(ERR_EXPECTING_KEY).expect("Cant't get err key Json"));
    let mut json = BTreeMap::new();
    json.insert("foo".to_string(), Json::String("bar".to_string()));
    assert_eq!(error_json_with("foo".to_string(), json),
               Json::from_str(ERR_JSON_WITH_FOO).expect("Can't get foo err Json"));
}

<|endoftext|>


<commit_before>

// -*- rust -*-
use std;
import std::rand;
import std::str;

#[test]
fn test() {
    let r1: rand::rng = rand::mk_rng();
    log r1.next();
    log r1.next();
    {
        let r2 = rand::mk_rng();
        log r1.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r2.next();
    }
    log r1.next();
    log r1.next();
}

#[test]
fn genstr() {
    let r: rand::rng = rand::mk_rng();
    log r.gen_str(10u);
    log r.gen_str(10u);
    log r.gen_str(10u);
    assert(str::char_len(r.gen_str(10u)) == 10u);
    assert(str::char_len(r.gen_str(16u)) == 16u);
}
<commit_msg>Copy first batch of material from libstd to libcore.<commit_after>import core::*;

// -*- rust -*-
use std;
import std::rand;
import str;

#[test]
fn test() {
    let r1: rand::rng = rand::mk_rng();
    log r1.next();
    log r1.next();
    {
        let r2 = rand::mk_rng();
        log r1.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r1.next();
        log r1.next();
        log r1.next();
        log r2.next();
        log r2.next();
        log r2.next();
    }
    log r1.next();
    log r1.next();
}

#[test]
fn genstr() {
    let r: rand::rng = rand::mk_rng();
    log r.gen_str(10u);
    log r.gen_str(10u);
    log r.gen_str(10u);
    assert(str::char_len(r.gen_str(10u)) == 10u);
    assert(str::char_len(r.gen_str(16u)) == 16u);
}
<|endoftext|>


<commit_before>extern crate crossbeam;
use std;
use decoders::NUM_CORES;
use std::mem;

extern crate byteorder;
use self::byteorder::{BigEndian, LittleEndian, ByteOrder};

#[derive(Debug, Copy, Clone)]
pub struct Endian {
  big: bool,
}

impl Endian {
  pub fn ru32(&self, buf: &[u8], pos: usize) -> u32 {
    if self.big {
      BEu32(buf,pos)
    } else {
      LEu32(buf,pos)
    }
  }

  pub fn ru16(&self, buf: &[u8], pos: usize) -> u16 {
    if self.big {
      BEu16(buf,pos)
    } else {
      LEu16(buf,pos)
    }
  }
}

pub static BIG_ENDIAN: Endian = Endian{big: true};
pub static LITTLE_ENDIAN: Endian = Endian{big: false};

#[allow(non_snake_case)] #[inline] pub fn BEu32(buf: &[u8], pos: usize) -> u32 {
  BigEndian::read_u32(&buf[pos..pos+4])
}

#[allow(non_snake_case)] #[inline] pub fn LEu32(buf: &[u8], pos: usize) -> u32 {
  LittleEndian::read_u32(&buf[pos..pos+4])
}

#[allow(non_snake_case)] #[inline] pub fn BEu16(buf: &[u8], pos: usize) -> u16 {
  BigEndian::read_u16(&buf[pos..pos+2])
}

#[allow(non_snake_case)] #[inline] pub fn LEu16(buf: &[u8], pos: usize) -> u16 {
  LittleEndian::read_u16(&buf[pos..pos+2])
}

pub fn decode_12be(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*12/8) as usize)..];

    for (o, i) in out.chunks_mut(2).zip(inb.chunks(3)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;
      let g3: u16 = i[2] as u16;

      o[0] = (g1 << 4) | (g2 >> 4);
      o[1] = ((g2 & 0x0f) << 8) | g3;
    }
  }))
}

pub fn decode_12le(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*12/8) as usize)..];

    for (o, i) in out.chunks_mut(2).zip(inb.chunks(3)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;
      let g3: u16 = i[2] as u16;

      o[0] = ((g2 & 0x0f) << 8) | g1;
      o[1] = (g3 << 4) | (g2 >> 4);
    }
  }))
}

pub fn decode_12be_unpacked(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*2) as usize)..];

    for (o, i) in out.chunks_mut(1).zip(inb.chunks(2)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;

      o[0] = ((g1 & 0x0f) << 8) | g2;
    }
  }))
}

pub fn decode_16le(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*2) as usize)..];

    for (o, i) in out.chunks_mut(1).zip(inb.chunks(2)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;

      o[0] = (g2 << 8) | g1;
    }
  }))
}

pub fn decode_threaded<F>(width: usize, height: usize, closure: &F) -> Vec<u16>
  where F : Fn(&mut [u16], usize, usize, usize)+std::marker::Sync {
  let mut out: Vec<u16> = vec![0; (width*height) as usize];

  // Default to the number of available physical cores (no hyperthreading)
  let threads = *NUM_CORES;

  // If we're only using one thread do it all sequentially and be done with it
  if threads < 2 || height < threads {
    closure(&mut out, 0, width, height);
    return out
  }

  let mut split = height/threads;
  if split*threads < height { // Make sure the last split is always the smallest
    split += 1;
  }

  crossbeam::scope(|scope| {
    let mut handles = Vec::new();
    for (i,out_part) in (&mut out[..]).chunks_mut(split*width).enumerate() {
      let start = split*(i);
      let tall = out_part.len()/width;
      let handle = scope.spawn(move || {
        closure(out_part, start, width, tall);
      });
      handles.push(handle);
    }

    for h in handles { h.join() };
  });

  out
}

#[derive(Debug, Clone)]
pub struct LookupTable {
  table: Vec<(u16, u16, u16)>,
}

impl LookupTable {
  pub fn new(table: &[u16]) -> LookupTable {
    let mut tbl = vec![(0,0,0); table.len()];
    for i in 0..table.len() {
      let center = table[i];
      let lower = if i > 0 {table[i-1]} else {center};
      let upper = if i < (table.len()-1) {table[i+1]} else {center};
      let base = center - ((upper - lower + 2) / 4);
      let delta = upper - lower;
      tbl[i] = (center, base, delta);
    }
    LookupTable {
      table: tbl,
    }
  }

//  pub fn lookup(&self, value: u16) -> u16 {
//    let (val, _, _) = self.table[value as usize];
//    val
//  }

  pub fn dither(&self, value: u16, rand: &mut u32) -> u16 {
    let (_, sbase, sdelta) = self.table[value as usize];
    let base = sbase as u32;
    let delta = sdelta as u32;
    let pixel = base + ((delta * (*rand & 2047) + 1024) >> 12);
    *rand = 15700 * (*rand & 65535) + (*rand >> 16);
    pixel as u16
  }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PumpOrder {
  LSB,
  MSB,
}

pub struct BitPump<'a> {
  buffer: &'a [u8],
  pos: usize,
  bits: u64,
  nbits: u32,
  order: PumpOrder,
}

impl<'a> BitPump<'a> {
  pub fn new(src: &'a [u8], order: PumpOrder) -> BitPump {
    BitPump {
      buffer: src,
      pos: 0,
      bits: 0,
      nbits: 0,
      order: order,
    }
  }

  fn fill_bits(&mut self) {
    if self.order == PumpOrder::MSB {
      let mut bytes: [u8;8] = unsafe{mem::transmute(self.bits)};
      let fillbytes = (64-self.nbits) / 8;
      for i in 0..(8-fillbytes) {
        bytes[(7-i) as usize] = bytes[(7-i-fillbytes) as usize];
      }
      for i in 0..fillbytes {
        bytes[(fillbytes-i-1) as usize] = self.buffer[self.pos];
        self.pos += 1;
      }
      self.bits = unsafe{mem::transmute(bytes)};
      self.nbits += fillbytes*8;
    } else {
      let inbits: u64 = LEu32(self.buffer, self.pos) as u64;
      self.pos += 4;
      self.bits = ((inbits << 32) | (self.bits << (32-self.nbits))) >> (32-self.nbits);
      self.nbits += 32;
    }
  }

  pub fn peek_bits(&mut self, num: u32) -> u32 {
    if num > self.nbits {
      self.fill_bits();
    }
    if self.order == PumpOrder::MSB {
      (self.bits >> (self.nbits-num)) as u32
    } else {
      (self.bits & (0x0ffffffffu64 >> (32-num))) as u32
    }
  }

  pub fn get_bits(&mut self, num: u32) -> u32 {
    if num == 0 {
      return 0
    }

    let val = self.peek_bits(num);
    self.nbits -= num;
    if self.order == PumpOrder::MSB {
      self.bits &= (1 << self.nbits) - 1;
    } else {
      self.bits >>= num;
    }
    val
  }

  pub fn get_ibits(&mut self, num: u32) -> i32 {
    let val = self.get_bits(num);
    unsafe{mem::transmute(val)}
  }
}
<commit_msg>Simplify and speedup MSB BitPump fill<commit_after>extern crate crossbeam;
use std;
use decoders::NUM_CORES;
use std::mem;

extern crate byteorder;
use self::byteorder::{BigEndian, LittleEndian, ByteOrder};

#[derive(Debug, Copy, Clone)]
pub struct Endian {
  big: bool,
}

impl Endian {
  pub fn ru32(&self, buf: &[u8], pos: usize) -> u32 {
    if self.big {
      BEu32(buf,pos)
    } else {
      LEu32(buf,pos)
    }
  }

  pub fn ru16(&self, buf: &[u8], pos: usize) -> u16 {
    if self.big {
      BEu16(buf,pos)
    } else {
      LEu16(buf,pos)
    }
  }
}

pub static BIG_ENDIAN: Endian = Endian{big: true};
pub static LITTLE_ENDIAN: Endian = Endian{big: false};

#[allow(non_snake_case)] #[inline] pub fn BEu32(buf: &[u8], pos: usize) -> u32 {
  BigEndian::read_u32(&buf[pos..pos+4])
}

#[allow(non_snake_case)] #[inline] pub fn LEu32(buf: &[u8], pos: usize) -> u32 {
  LittleEndian::read_u32(&buf[pos..pos+4])
}

#[allow(non_snake_case)] #[inline] pub fn BEu16(buf: &[u8], pos: usize) -> u16 {
  BigEndian::read_u16(&buf[pos..pos+2])
}

#[allow(non_snake_case)] #[inline] pub fn LEu16(buf: &[u8], pos: usize) -> u16 {
  LittleEndian::read_u16(&buf[pos..pos+2])
}

pub fn decode_12be(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*12/8) as usize)..];

    for (o, i) in out.chunks_mut(2).zip(inb.chunks(3)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;
      let g3: u16 = i[2] as u16;

      o[0] = (g1 << 4) | (g2 >> 4);
      o[1] = ((g2 & 0x0f) << 8) | g3;
    }
  }))
}

pub fn decode_12le(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*12/8) as usize)..];

    for (o, i) in out.chunks_mut(2).zip(inb.chunks(3)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;
      let g3: u16 = i[2] as u16;

      o[0] = ((g2 & 0x0f) << 8) | g1;
      o[1] = (g3 << 4) | (g2 >> 4);
    }
  }))
}

pub fn decode_12be_unpacked(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*2) as usize)..];

    for (o, i) in out.chunks_mut(1).zip(inb.chunks(2)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;

      o[0] = ((g1 & 0x0f) << 8) | g2;
    }
  }))
}

pub fn decode_16le(buf: &[u8], width: usize, height: usize) -> Vec<u16> {
  decode_threaded(width, height, &(|out: &mut [u16], start, width, _| {
    let inb = &buf[((start*width*2) as usize)..];

    for (o, i) in out.chunks_mut(1).zip(inb.chunks(2)) {
      let g1: u16 = i[0] as u16;
      let g2: u16 = i[1] as u16;

      o[0] = (g2 << 8) | g1;
    }
  }))
}

pub fn decode_threaded<F>(width: usize, height: usize, closure: &F) -> Vec<u16>
  where F : Fn(&mut [u16], usize, usize, usize)+std::marker::Sync {
  let mut out: Vec<u16> = vec![0; (width*height) as usize];

  // Default to the number of available physical cores (no hyperthreading)
  let threads = *NUM_CORES;

  // If we're only using one thread do it all sequentially and be done with it
  if threads < 2 || height < threads {
    closure(&mut out, 0, width, height);
    return out
  }

  let mut split = height/threads;
  if split*threads < height { // Make sure the last split is always the smallest
    split += 1;
  }

  crossbeam::scope(|scope| {
    let mut handles = Vec::new();
    for (i,out_part) in (&mut out[..]).chunks_mut(split*width).enumerate() {
      let start = split*(i);
      let tall = out_part.len()/width;
      let handle = scope.spawn(move || {
        closure(out_part, start, width, tall);
      });
      handles.push(handle);
    }

    for h in handles { h.join() };
  });

  out
}

#[derive(Debug, Clone)]
pub struct LookupTable {
  table: Vec<(u16, u16, u16)>,
}

impl LookupTable {
  pub fn new(table: &[u16]) -> LookupTable {
    let mut tbl = vec![(0,0,0); table.len()];
    for i in 0..table.len() {
      let center = table[i];
      let lower = if i > 0 {table[i-1]} else {center};
      let upper = if i < (table.len()-1) {table[i+1]} else {center};
      let base = center - ((upper - lower + 2) / 4);
      let delta = upper - lower;
      tbl[i] = (center, base, delta);
    }
    LookupTable {
      table: tbl,
    }
  }

//  pub fn lookup(&self, value: u16) -> u16 {
//    let (val, _, _) = self.table[value as usize];
//    val
//  }

  pub fn dither(&self, value: u16, rand: &mut u32) -> u16 {
    let (_, sbase, sdelta) = self.table[value as usize];
    let base = sbase as u32;
    let delta = sdelta as u32;
    let pixel = base + ((delta * (*rand & 2047) + 1024) >> 12);
    *rand = 15700 * (*rand & 65535) + (*rand >> 16);
    pixel as u16
  }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PumpOrder {
  LSB,
  MSB,
}

pub struct BitPump<'a> {
  buffer: &'a [u8],
  pos: usize,
  bits: u64,
  nbits: u32,
  order: PumpOrder,
}

impl<'a> BitPump<'a> {
  pub fn new(src: &'a [u8], order: PumpOrder) -> BitPump {
    BitPump {
      buffer: src,
      pos: 0,
      bits: 0,
      nbits: 0,
      order: order,
    }
  }

  fn fill_bits(&mut self) {
    if self.order == PumpOrder::MSB {
      let inbits: u64 = BEu32(self.buffer, self.pos) as u64;
      self.bits = (self.bits << 32) | inbits;
    } else {
      let inbits: u64 = LEu32(self.buffer, self.pos) as u64;
      self.bits = ((inbits << 32) | (self.bits << (32-self.nbits))) >> (32-self.nbits);
    }
    self.pos += 4;
    self.nbits += 32;
  }

  pub fn peek_bits(&mut self, num: u32) -> u32 {
    if num > self.nbits {
      self.fill_bits();
    }
    if self.order == PumpOrder::MSB {
      (self.bits >> (self.nbits-num)) as u32
    } else {
      (self.bits & (0x0ffffffffu64 >> (32-num))) as u32
    }
  }

  pub fn get_bits(&mut self, num: u32) -> u32 {
    if num == 0 {
      return 0
    }

    let val = self.peek_bits(num);
    self.nbits -= num;
    if self.order == PumpOrder::MSB {
      self.bits &= (1 << self.nbits) - 1;
    } else {
      self.bits >>= num;
    }
    val
  }

  pub fn get_ibits(&mut self, num: u32) -> i32 {
    let val = self.get_bits(num);
    unsafe{mem::transmute(val)}
  }
}
<|endoftext|>


<commit_before>use cargo_platform::Cfg;

use crate::core::compiler::{CompileKind, RustcTargetData};
use crate::util::CargoResult;

use std::collections::HashMap;
use std::io::Write;

const VERSION: u32 = 1;

// {
// "version": 1,
// "host": {
//      "names": ["windows", "debug_assertions"],
//      "key_pairs": [
//          {"target_os": "windows"},
//          {"target_vendor": "pc"}
//      ]
// },
// "targets": [
//      "x86_64-pc-windows-msvc": {
//          "names": ["windows", "debug_assertions"],
//          "key_pairs": [
//              {"target_os": "windows"},
//              {"target_vendor": "pc"}
//          ]
//      }
// ]
// }

// {
//     "version": 1,
//     "host": {
//         "names": ["windows", "debug_assertions"],
//         "arch":"x86_64",
//         "endian":"little",
//         "env":"msvc",
//         "family":"windows",
//         "features":["fxsr","sse","sse2"],
//         "os":"windows",
//         "pointer_width":"64",
//         "vendor":"pc"
//     }
// }

#[derive(serde::Serialize)]
struct SerializedRustcCfg<'a> {
    version: u32,
    host: SerializedCfg<'a>,
    targets: HashMap<&'a str, SerializedCfg<'a>>,
}

#[derive(serde::Serialize)]
struct SerializedCfg<'a> {
    names: Vec<&'a str>,
    key_pairs: Vec<HashMap<&'a str, &'a str>>,
}

impl<'a> SerializedCfg<'a> {
    fn new(rtd: &'a RustcTargetData, kind: CompileKind) -> Self {
        Self {
            names: rtd.cfg(kind).iter().filter_map(|c| {
                match c {
                    Cfg::Name(s) => Some(s.as_str()),
                    Cfg::KeyPair(..) => None,
                }
            }).collect(),
            key_pairs: rtd.cfg(kind).iter().filter_map(|c| {
                match c {
                    Cfg::Name(..) => None,
                    Cfg::KeyPair(k, v) => {
                        let mut pair = HashMap::with_capacity(1);
                        pair.insert(k.as_str(), v.as_str());
                        Some(pair)
                    }
                }
            }).collect()
        }
    }
}

pub fn emit_serialized_rustc_cfg(rtd: &RustcTargetData, kinds: &[CompileKind]) -> CargoResult<()> {
    let host = SerializedCfg::new(rtd, CompileKind::Host);
    let targets = kinds.iter().filter_map(|k| {
         match k {
            CompileKind::Host => None,
            CompileKind::Target(ct) => Some((ct.short_name(), SerializedCfg::new(rtd, *k))),
         }
    }).collect();
    let s = SerializedRustcCfg {
        version: VERSION,
        host,
        targets
    };
    let stdout = std::io::stdout();
    let mut lock = stdout.lock();
    serde_json::to_writer(&mut lock, &s)?;
    drop(writeln!(lock));
    Ok(())
}
<commit_msg>Change JSON format<commit_after>use cargo_platform::Cfg;

use crate::core::compiler::{CompileKind, RustcTargetData};
use crate::util::CargoResult;

use std::collections::HashMap;
use std::io::Write;

const VERSION: u32 = 1;

// {
//     "version": 1,
//     "host": {
//         "names": ["windows", "debug_assertions"],
//         "arch":"x86_64",
//         "endian":"little",
//         "env":"msvc",
//         "family":"windows",
//         "features":["fxsr","sse","sse2"],
//         "os":"windows",
//         "pointer_width":"64",
//         "vendor":"pc"
//     },
//     "targets": [
//         "x86_64-unknown-linux-gnu": {
//             "names": ["debug_assertions", "unix"],
//             "arch":"x86_64",
//             "endian":"little",
//             "env":"gnu",
//             "family":"unix",
//             "features": ["fxsr","sse","sse2"],
//             "os":"linux",
//             "pointer_width":"64",
//             "vendor":"unknown"
//         }
//     ]
// }

#[derive(serde::Serialize)]
struct SerializedRustcCfg<'a> {
    version: u32,
    host: SerializedCfg<'a>,
    targets: HashMap<&'a str, SerializedCfg<'a>>,
}

#[derive(serde::Serialize)]
struct SerializedCfg<'a> {
    arch: Option<&'a str>,
    endian: Option<&'a str>,
    env: Option<&'a str>,
    family: Option<&'a str>,
    features: Vec<&'a str>,
    names: Vec<&'a str>,
    os: Option<&'a str>,
    pointer_width: Option<&'a str>,
    vendor: Option<&'a str>,
}

impl<'a> SerializedCfg<'a> {
    fn new(rtd: &'a RustcTargetData, kind: CompileKind) -> Self {
        let features = rtd.cfg(kind).iter().filter_map(|c| {
            match c {
                Cfg::Name(..) => None,
                Cfg::KeyPair(k, v) => {
                    if k == "target_feature" {
                        Some(v.as_str())
                    } else {
                        None
                    }
                }
            }
        }).collect();
        let names = rtd.cfg(kind).iter().filter_map(|c| {
            match c {
                Cfg::Name(s) => Some(s.as_str()),
                Cfg::KeyPair(..) => None,
            }
        }).collect();
        Self {
            arch: Self::find(rtd, kind, "target_arch"),
            endian: Self::find(rtd, kind, "target_endian"),
            env: Self::find(rtd, kind, "target_env"),
            family: Self::find(rtd, kind, "target_family"),
            features,
            names,
            os: Self::find(rtd, kind, "target_os"),
            pointer_width: Self::find(rtd, kind, "target_pointer_width"),
            vendor: Self::find(rtd, kind, "target_vendor"),
        }
    }

    fn find(rtd: &'a RustcTargetData, kind: CompileKind, key: &str) -> Option<&'a str> {
         rtd.cfg(kind).iter().find_map(|c| {
            match c {
                Cfg::Name(..) => None,
                Cfg::KeyPair(k, v) =>
                    if k == key {
                        Some(v.as_str())
                    } else {
                        None
                    }
            }
        })
    }
}

pub fn emit_serialized_rustc_cfg(rtd: &RustcTargetData, kinds: &[CompileKind]) -> CargoResult<()> {
    let host = SerializedCfg::new(rtd, CompileKind::Host);
    let targets = kinds.iter().filter_map(|k| {
         match k {
            CompileKind::Host => None,
            CompileKind::Target(ct) => Some((ct.short_name(), SerializedCfg::new(rtd, *k))),
         }
    }).collect();
    let s = SerializedRustcCfg {
        version: VERSION,
        host,
        targets
    };
    let stdout = std::io::stdout();
    let mut lock = stdout.lock();
    serde_json::to_writer(&mut lock, &s)?;
    drop(writeln!(lock));
    Ok(())
}
<|endoftext|>


<commit_before>//! The `zcode` module contains a lot of useful functionality
//! to deal with all the zcode related stuff

pub mod zbytes;
pub mod zfile;
pub mod ztext;

use std::error::Error;
use std::io::Write;
use self::zfile::Zfile;

/// an example to show the current status of the z-code implementation
/// zcode playground function
pub fn temp_create_zcode_example<W: Write>(output: &mut W) {

    let mut zfile: Zfile = zfile::Zfile::new();

    zfile.start();
    zfile.op_call_1n("Start");

    zfile.routine("Start", 0);
    zfile.op_print("start passage");
    zfile.op_newline();

    zfile.op_quit();
    zfile.end();

    match output.write_all(&(*zfile.data.bytes)) {
        Err(why) => {
            panic!("Could not write to output: {}", Error::description(&why));
        },
        Ok(_) => {
            info!("Wrote zcode to output");
        }
    };
}
<commit_msg>update the zcode-test-sample, op_print shouldn't used only with gen_print_ops<commit_after>//! The `zcode` module contains a lot of useful functionality
//! to deal with all the zcode related stuff

pub mod zbytes;
pub mod zfile;
pub mod ztext;

use std::error::Error;
use std::io::Write;
use self::zfile::Zfile;

/// an example to show the current status of the z-code implementation
/// zcode playground function
pub fn temp_create_zcode_example<W: Write>(output: &mut W) {

    let mut zfile: Zfile = zfile::Zfile::new();

    zfile.start();
    zfile.op_call_1n("Start");

    zfile.routine("Start", 0);
    zfile.gen_print_ops("start passage");
    zfile.op_newline();

    zfile.op_quit();
    zfile.end();

    match output.write_all(&(*zfile.data.bytes)) {
        Err(why) => {
            panic!("Could not write to output: {}", Error::description(&why));
        },
        Ok(_) => {
            info!("Wrote zcode to output");
        }
    };
}
<|endoftext|>


<commit_before>//! System operations instructions

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

#[cfg(not(feature = "std"))] use alloc::rc::Rc;
#[cfg(feature = "std")] use std::rc::Rc;

use bigint::{U256, M256, H256, Address, Gas};
use ::{Memory, Log, ValidTransaction, Patch};
use eval::util::{l64, copy_from_memory};
use block_core::TransactionAction;
use super::{Control, State};

#[cfg(feature = "std")] use std::cmp::min;
#[cfg(not(feature = "std"))] use core::cmp::min;

use sha3::{Digest, Keccak256};

pub fn suicide<M: Memory + Default, P: Patch>(state: &mut State<M, P>) {
    pop!(state, address: Address);
    let balance = state.account_state.balance(state.context.address).unwrap();
    if !state.removed.contains(&state.context.address) {
        state.removed.push(state.context.address);
    }
    state.account_state.increase_balance(address, balance);

    let balance = state.account_state.balance(state.context.address).unwrap();
    state.account_state.decrease_balance(state.context.address, balance);
}

pub fn log<M: Memory + Default, P: Patch>(state: &mut State<M, P>, topic_len: usize) {
    pop!(state, index: U256, len: U256);
    let data = copy_from_memory(&state.memory, index, len);
    let mut topics = Vec::new();
    for _ in 0..topic_len {
        topics.push(H256::from(state.stack.pop().unwrap()));
    }

    state.logs.push(Log {
        address: state.context.address,
        data,
        topics,
    });
}

pub fn sha3<M: Memory + Default, P: Patch>(state: &mut State<M, P>) {
    pop!(state, from: U256, len: U256);
    let data = copy_from_memory(&state.memory, from, len);
    let ret = Keccak256::digest(data.as_slice());
    push!(state, M256::from(ret.as_slice()));
}

macro_rules! try_callstack_limit {
    ( $state:expr, $patch:tt ) => {
        if $state.depth > $patch::callstack_limit() {
            push!($state, M256::zero());
            return None;
        }
    }
}

macro_rules! try_balance {
    ( $state:expr, $value:expr, $gas:expr ) => {
        if $state.account_state.balance($state.context.address).unwrap() < $value {
            push!($state, M256::zero());
            return None;
        }
    }
}

pub fn create<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    do_create(state, after_gas, false)
}

pub fn create2<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    do_create(state, after_gas, true)
}

fn do_create<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas, is_create2: bool) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, value: U256);
    pop!(state, init_start: U256, init_len: U256);

    try_callstack_limit!(state, P);
    try_balance!(state, value, Gas::zero());

    let init = Rc::new(copy_from_memory(&state.memory, init_start, init_len));
    let transaction = if !is_create2 {
        ValidTransaction {
            caller: Some(state.context.address),
            gas_price: state.context.gas_price,
            gas_limit: l64_after_gas,
            value,
            input: init,
            action: TransactionAction::Create,
            nonce: state.account_state.nonce(state.context.address).unwrap(),
        }
    } else {
        pop!(state, salt: H256);
        ValidTransaction {
            caller: Some(state.context.address),
            gas_price: state.context.gas_price,
            gas_limit: l64_after_gas,
            value,
            input: init.clone(),
            action: TransactionAction::Create2(salt, init),
            nonce: state.account_state.nonce(state.context.address).unwrap(),
        }
    };

    let context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();

    push!(state, context.address.into());
    Some(Control::InvokeCreate(context))
}

pub fn call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, stipend_gas: Gas, after_gas: Gas, as_self: bool) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address, value: U256);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas) + stipend_gas;

    try_callstack_limit!(state, P);
    try_balance!(state, value, gas_limit);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.address),
        gas_price: state.context.gas_price,
        gas_limit,
        value,
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let mut context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();
    if as_self {
        context.address = state.context.address;
    }

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}

pub fn static_call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, stipend_gas: Gas, after_gas: Gas) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas) + stipend_gas;

    try_callstack_limit!(state, P);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.address),
        gas_price: state.context.gas_price,
        gas_limit,
        value: U256::zero(),
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        true,
    ).unwrap();

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}

pub fn delegate_call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas);

    try_callstack_limit!(state, P);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.caller),
        gas_price: state.context.gas_price,
        gas_limit,
        value: state.context.value,
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let mut context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();
    context.value = U256::zero();
    context.address = state.context.address;

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}
<commit_msg>pre-calculate code_hash for the TransactionAction<commit_after>//! System operations instructions

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

#[cfg(not(feature = "std"))] use alloc::rc::Rc;
#[cfg(feature = "std")] use std::rc::Rc;

use bigint::{U256, M256, H256, Address, Gas};
use ::{Memory, Log, ValidTransaction, Patch};
use eval::util::{l64, copy_from_memory};
use block_core::TransactionAction;
use super::{Control, State};

#[cfg(feature = "std")] use std::cmp::min;
#[cfg(not(feature = "std"))] use core::cmp::min;

use sha3::{Digest, Keccak256};

pub fn suicide<M: Memory + Default, P: Patch>(state: &mut State<M, P>) {
    pop!(state, address: Address);
    let balance = state.account_state.balance(state.context.address).unwrap();
    if !state.removed.contains(&state.context.address) {
        state.removed.push(state.context.address);
    }
    state.account_state.increase_balance(address, balance);

    let balance = state.account_state.balance(state.context.address).unwrap();
    state.account_state.decrease_balance(state.context.address, balance);
}

pub fn log<M: Memory + Default, P: Patch>(state: &mut State<M, P>, topic_len: usize) {
    pop!(state, index: U256, len: U256);
    let data = copy_from_memory(&state.memory, index, len);
    let mut topics = Vec::new();
    for _ in 0..topic_len {
        topics.push(H256::from(state.stack.pop().unwrap()));
    }

    state.logs.push(Log {
        address: state.context.address,
        data,
        topics,
    });
}

pub fn sha3<M: Memory + Default, P: Patch>(state: &mut State<M, P>) {
    pop!(state, from: U256, len: U256);
    let data = copy_from_memory(&state.memory, from, len);
    let ret = Keccak256::digest(data.as_slice());
    push!(state, M256::from(ret.as_slice()));
}

macro_rules! try_callstack_limit {
    ( $state:expr, $patch:tt ) => {
        if $state.depth > $patch::callstack_limit() {
            push!($state, M256::zero());
            return None;
        }
    }
}

macro_rules! try_balance {
    ( $state:expr, $value:expr, $gas:expr ) => {
        if $state.account_state.balance($state.context.address).unwrap() < $value {
            push!($state, M256::zero());
            return None;
        }
    }
}

pub fn create<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    do_create(state, after_gas, false)
}

pub fn create2<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    do_create(state, after_gas, true)
}

fn do_create<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas, is_create2: bool) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, value: U256);
    pop!(state, init_start: U256, init_len: U256);

    try_callstack_limit!(state, P);
    try_balance!(state, value, Gas::zero());

    let init = Rc::new(copy_from_memory(&state.memory, init_start, init_len));
    let transaction = if !is_create2 {
        ValidTransaction {
            caller: Some(state.context.address),
            gas_price: state.context.gas_price,
            gas_limit: l64_after_gas,
            value,
            input: init,
            action: TransactionAction::Create,
            nonce: state.account_state.nonce(state.context.address).unwrap(),
        }
    } else {
        pop!(state, salt: H256);
        let init_hash = Keccak256::digest(&init);
        let init_hash = M256::from(&init_hash[..]);
        ValidTransaction {
            caller: Some(state.context.address),
            gas_price: state.context.gas_price,
            gas_limit: l64_after_gas,
            value,
            input: init.clone(),
            action: TransactionAction::Create2(salt, init_hash),
            nonce: state.account_state.nonce(state.context.address).unwrap(),
        }
    };

    let context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();

    push!(state, context.address.into());
    Some(Control::InvokeCreate(context))
}

pub fn call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, stipend_gas: Gas, after_gas: Gas, as_self: bool) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address, value: U256);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas) + stipend_gas;

    try_callstack_limit!(state, P);
    try_balance!(state, value, gas_limit);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.address),
        gas_price: state.context.gas_price,
        gas_limit,
        value,
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let mut context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();
    if as_self {
        context.address = state.context.address;
    }

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}

pub fn static_call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, stipend_gas: Gas, after_gas: Gas) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas) + stipend_gas;

    try_callstack_limit!(state, P);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.address),
        gas_price: state.context.gas_price,
        gas_limit,
        value: U256::zero(),
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        true,
    ).unwrap();

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}

pub fn delegate_call<M: Memory + Default, P: Patch>(state: &mut State<M, P>, after_gas: Gas) -> Option<Control> {
    let l64_after_gas = if P::call_create_l64_after_gas() { l64(after_gas) } else { after_gas };

    pop!(state, gas: Gas, to: Address);
    pop!(state, in_start: U256, in_len: U256, out_start: U256, out_len: U256);
    let gas_limit = min(gas, l64_after_gas);

    try_callstack_limit!(state, P);

    let input = Rc::new(copy_from_memory(&state.memory, in_start, in_len));
    let transaction = ValidTransaction {
        caller: Some(state.context.caller),
        gas_price: state.context.gas_price,
        gas_limit,
        value: state.context.value,
        input,
        action: TransactionAction::Call(to),
        nonce: state.account_state.nonce(state.context.address).unwrap(),
    };

    let mut context = transaction.into_context::<P>(
        Gas::zero(), Some(state.context.origin), &mut state.account_state, true,
        state.context.is_static,
    ).unwrap();
    context.value = U256::zero();
    context.address = state.context.address;

    push!(state, M256::from(1u64));
    Some(Control::InvokeCall(context, (out_start, out_len)))
}
<|endoftext|>


<commit_before>//! Core tests
//!
//! Run the existing testsuite as a Rust unit test.

use bootsim::{
    DepTest, DepType, UpgradeInfo,
    ImagesBuilder,
    Images,
    NO_DEPS,
    testlog,
};
use std::{
    env,
    sync::atomic::{AtomicUsize, Ordering},
};

/// A single test, after setting up logging and such.  Within the $body,
/// $arg will be bound to each device.
macro_rules! test_shell {
    ($name:ident, $arg: ident, $body:expr) => {
        #[test]
        fn $name() {
            testlog::setup();
            ImagesBuilder::each_device(|$arg| {
                $body;
            });
        }
    }
}

/// A typical test calls a particular constructor, and runs a given test on
/// that constructor.
macro_rules! sim_test {
    ($name:ident, $maker:ident($($margs:expr),*), $test:ident($($targs:expr),*)) => {
        test_shell!($name, r, {
            let image = r.$maker($($margs),*);
            dump_image(&image, stringify!($name));
            assert!(!image.$test($($targs),*));
        });
    };
}

sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgrade());
sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS), run_norevert_newimage());
sim_test!(basic_revert, make_image(&NO_DEPS, true), run_basic_revert());
sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails());
sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails());
sim_test!(perm_with_random_fails, make_image(&NO_DEPS, true), run_perm_with_random_fails(5));
sim_test!(norevert, make_image(&NO_DEPS, true), run_norevert());
sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_status_fails_complete());
sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset());

// Test various combinations of incorrect dependencies.
test_shell!(dependency_combos, r, {
    // Only test setups with two images.
    if r.num_images() != 2 {
        return;
    }

    for dep in TEST_DEPS {
        let image = r.clone().make_image(&dep, true);
        dump_image(&image, "dependency_combos");
        assert!(!image.run_check_deps(&dep));
    }
});

/// These are the variants of dependencies we will test.
pub static TEST_DEPS: &[DepTest] = &[
    // First is a sanity test, no dependencies should upgrade.
    DepTest {
        depends: [DepType::Nothing, DepType::Nothing],
        upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
    },

    // If all of the dependencies are unmet, there should be no upgrades.
    // TODO: Disabled because it fails.
    /*
    DepTest {
        depends: [DepType::Newer, DepType::Newer],
        upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
    },
    */
];

/// Counter for the image number.
static IMAGE_NUMBER: AtomicUsize = AtomicUsize::new(0);

/// Dump an image if that makes sense.  The name is the name of the test
/// being run.  If the MCUBOT_DEBUG_DUMP environment variable contains, in
/// one of its comma separate strings a substring of this name, then this
/// image will be dumped.  As a special case, we will dump everything if
/// this environment variable is set to all.
fn dump_image(image: &Images, name: &str) {
    if let Ok(request) = env::var("MCUBOOT_DEBUG_DUMP") {
        if request.split(',').any(|req| {
            req == "all" || name.contains(req)
        }) {
            let count = IMAGE_NUMBER.fetch_add(1, Ordering::SeqCst);
            let full_name = format!("{}-{:04}", name, count);
            log::info!("Dump {:?}", full_name);
            image.debug_dump(&full_name);
        }
    }
}
<commit_msg>Uncomment hold and add correct upgrades<commit_after>//! Core tests
//!
//! Run the existing testsuite as a Rust unit test.

use bootsim::{
    DepTest, DepType, UpgradeInfo,
    ImagesBuilder,
    Images,
    NO_DEPS,
    testlog,
};
use std::{
    env,
    sync::atomic::{AtomicUsize, Ordering},
};

/// A single test, after setting up logging and such.  Within the $body,
/// $arg will be bound to each device.
macro_rules! test_shell {
    ($name:ident, $arg: ident, $body:expr) => {
        #[test]
        fn $name() {
            testlog::setup();
            ImagesBuilder::each_device(|$arg| {
                $body;
            });
        }
    }
}

/// A typical test calls a particular constructor, and runs a given test on
/// that constructor.
macro_rules! sim_test {
    ($name:ident, $maker:ident($($margs:expr),*), $test:ident($($targs:expr),*)) => {
        test_shell!($name, r, {
            let image = r.$maker($($margs),*);
            dump_image(&image, stringify!($name));
            assert!(!image.$test($($targs),*));
        });
    };
}

sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgrade());
sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS), run_norevert_newimage());
sim_test!(basic_revert, make_image(&NO_DEPS, true), run_basic_revert());
sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails());
sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails());
sim_test!(perm_with_random_fails, make_image(&NO_DEPS, true), run_perm_with_random_fails(5));
sim_test!(norevert, make_image(&NO_DEPS, true), run_norevert());
sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_status_fails_complete());
sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset());

// Test various combinations of incorrect dependencies.
test_shell!(dependency_combos, r, {
    // Only test setups with two images.
    if r.num_images() != 2 {
        return;
    }

    for dep in TEST_DEPS {
        let image = r.clone().make_image(&dep, true);
        dump_image(&image, "dependency_combos");
        assert!(!image.run_check_deps(&dep));
    }
});

/// These are the variants of dependencies we will test.
pub static TEST_DEPS: &[DepTest] = &[
    // First is a sanity test, no dependencies should upgrade.
    DepTest {
        depends: [DepType::Nothing, DepType::Nothing],
        upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
    },

    DepTest {
        depends: [DepType::Correct, DepType::Correct],
        upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
    },

    DepTest {
        depends: [DepType::Newer, DepType::Newer],
        upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
    },
];

/// Counter for the image number.
static IMAGE_NUMBER: AtomicUsize = AtomicUsize::new(0);

/// Dump an image if that makes sense.  The name is the name of the test
/// being run.  If the MCUBOT_DEBUG_DUMP environment variable contains, in
/// one of its comma separate strings a substring of this name, then this
/// image will be dumped.  As a special case, we will dump everything if
/// this environment variable is set to all.
fn dump_image(image: &Images, name: &str) {
    if let Ok(request) = env::var("MCUBOOT_DEBUG_DUMP") {
        if request.split(',').any(|req| {
            req == "all" || name.contains(req)
        }) {
            let count = IMAGE_NUMBER.fetch_add(1, Ordering::SeqCst);
            let full_name = format!("{}-{:04}", name, count);
            log::info!("Dump {:?}", full_name);
            image.debug_dump(&full_name);
        }
    }
}
<|endoftext|>