<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use arg_enum_proc_macro::ArgEnum;
use std::env;
use std::str::FromStr;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, ArgEnum)]
pub enum CpuFeatureLevel {
  RUST,
  SSE2,
  SSSE3,
  #[arg_enum(alias = "sse4.1")]
  SSE4_1,
  AVX2,
  AVX512,
  AVX512ICL,
}

impl CpuFeatureLevel {
  pub const fn len() -> usize {
    CpuFeatureLevel::AVX512ICL as usize + 1
  }

  #[inline(always)]
  pub fn as_index(self) -> usize {
    self as usize
  }
}

impl Default for CpuFeatureLevel {
  fn default() -> CpuFeatureLevel {
    fn avx512_detected() -> bool {
      is_x86_feature_detected!("avx512bw")
        && is_x86_feature_detected!("avx512cd")
        && is_x86_feature_detected!("avx512dq")
        && is_x86_feature_detected!("avx512f")
        && is_x86_feature_detected!("avx512vl")
    }
    fn avx512icl_detected() -> bool {
      avx512_detected()
        // && is_x86_feature_detected!("avx512bitalg")
        // && is_x86_feature_detected!("avx512clmulqdq")
        && is_x86_feature_detected!("avx512ifma")
        // && is_x86_feature_detected!("avx512vaes")
        && is_x86_feature_detected!("avx512vbmi")
        // && is_x86_feature_detected!("avx512vbmi2")
        && is_x86_feature_detected!("avx512vpopcntdq")
    }

    let detected: CpuFeatureLevel = if avx512icl_detected() {
      CpuFeatureLevel::AVX512ICL
    } else if avx512_detected() {
      CpuFeatureLevel::AVX512
    } else if is_x86_feature_detected!("avx2") {
      CpuFeatureLevel::AVX2
    } else if is_x86_feature_detected!("sse4.1") {
      CpuFeatureLevel::SSE4_1
    } else if is_x86_feature_detected!("ssse3") {
      CpuFeatureLevel::SSSE3
    } else if is_x86_feature_detected!("sse2") {
      CpuFeatureLevel::SSE2
    } else {
      CpuFeatureLevel::RUST
    };
    let manual: CpuFeatureLevel = match env::var("RAV1E_CPU_TARGET") {
      Ok(feature) => CpuFeatureLevel::from_str(&feature).unwrap_or(detected),
      Err(_e) => detected,
    };
    if manual > detected {
      detected
    } else {
      manual
    }
  }
}

// Create a static lookup table for CPUFeatureLevel enums
// Note: keys are CpuFeatureLevels without any prefix (no CpuFeatureLevel::)
macro_rules! cpu_function_lookup_table {
  ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
    $pub static $name: [$type; crate::cpu_features::CpuFeatureLevel::len()] = {
      use crate::cpu_features::CpuFeatureLevel;
      #[allow(unused_mut)]
      let mut out: [$type; CpuFeatureLevel::len()] = [$empty; CpuFeatureLevel::len()];

      // Can't use out[0][.] == $empty in static as of rust 1.40
      #[allow(unused_mut)]
      let mut set: [bool; CpuFeatureLevel::len()] = [false; CpuFeatureLevel::len()];

      #[allow(unused_imports)]
      use CpuFeatureLevel::*;
      $(
        out[$key as usize] = $value;
        set[$key as usize] = true;
      )*
      cpu_function_lookup_table!(waterfall_cpu_features(out, set, [SSE2, SSSE3, SSE4_1, AVX2, AVX512, AVX512ICL]));
      out
    };
  };

  // Fill empty output functions with the existent functions they support.
  // cpus should be in order of lowest cpu level to highest
  // Used like an internal function
  // Put in here to avoid adding more public macros
  (waterfall_cpu_features($out:ident, $set:ident, [$($cpu:ident),*])) => {
    // Use an array to emulate if statements (not supported in static as of
    // rust 1.40). Setting best[0] (false) and best[1] (true) is equivalent to
    // doing nothing and overriding our value respectively.
    #[allow(unused_assignments)]
    let mut best = [$out[0], $out[0]];
    $(
      // If the current entry has a function, update out best function.
      best[$set[$cpu as usize] as usize] = $out[$cpu as usize];
      // Update our current entry. Does nothing if it already had a function.
      $out[$cpu as usize] = best[1];
    )*
  };

  // version for default visibility
  ($name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
    cpu_function_lookup_table!(pub(self), $name: [$type], default: $empty, [$(($key, $value)),*]);
  };

  // use $name_$key as our values
  ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
    paste::item!{
      cpu_function_lookup_table!(
        $pub, $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
      );
    }
  };

  // version for default visibility
  ($name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
    cpu_function_lookup_table!(
      pub(self), $name: [$type], default: $empty, [$($key),*]
    );
  };
}
<commit_msg>Disable icelake detection<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use arg_enum_proc_macro::ArgEnum;
use std::env;
use std::str::FromStr;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, ArgEnum)]
pub enum CpuFeatureLevel {
  RUST,
  SSE2,
  SSSE3,
  #[arg_enum(alias = "sse4.1")]
  SSE4_1,
  AVX2,
  AVX512,
  AVX512ICL,
}

impl CpuFeatureLevel {
  pub const fn len() -> usize {
    CpuFeatureLevel::AVX512ICL as usize + 1
  }

  #[inline(always)]
  pub fn as_index(self) -> usize {
    self as usize
  }
}

impl Default for CpuFeatureLevel {
  fn default() -> CpuFeatureLevel {
    fn avx512_detected() -> bool {
      is_x86_feature_detected!("avx512bw")
        && is_x86_feature_detected!("avx512cd")
        && is_x86_feature_detected!("avx512dq")
        && is_x86_feature_detected!("avx512f")
        && is_x86_feature_detected!("avx512vl")
    }
    fn avx512icl_detected() -> bool {
      false
      // avx512_detected()
      // && is_x86_feature_detected!("avx512bitalg")
      // && is_x86_feature_detected!("avx512clmulqdq")
      // && is_x86_feature_detected!("avx512ifma")
      // && is_x86_feature_detected!("avx512vaes")
      // && is_x86_feature_detected!("avx512vbmi")
      // && is_x86_feature_detected!("avx512vbmi2")
      // && is_x86_feature_detected!("avx512vpopcntdq")
    }

    let detected: CpuFeatureLevel = if avx512icl_detected() {
      CpuFeatureLevel::AVX512ICL
    } else if avx512_detected() {
      CpuFeatureLevel::AVX512
    } else if is_x86_feature_detected!("avx2") {
      CpuFeatureLevel::AVX2
    } else if is_x86_feature_detected!("sse4.1") {
      CpuFeatureLevel::SSE4_1
    } else if is_x86_feature_detected!("ssse3") {
      CpuFeatureLevel::SSSE3
    } else if is_x86_feature_detected!("sse2") {
      CpuFeatureLevel::SSE2
    } else {
      CpuFeatureLevel::RUST
    };
    let manual: CpuFeatureLevel = match env::var("RAV1E_CPU_TARGET") {
      Ok(feature) => CpuFeatureLevel::from_str(&feature).unwrap_or(detected),
      Err(_e) => detected,
    };
    if manual > detected {
      detected
    } else {
      manual
    }
  }
}

// Create a static lookup table for CPUFeatureLevel enums
// Note: keys are CpuFeatureLevels without any prefix (no CpuFeatureLevel::)
macro_rules! cpu_function_lookup_table {
  ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
    $pub static $name: [$type; crate::cpu_features::CpuFeatureLevel::len()] = {
      use crate::cpu_features::CpuFeatureLevel;
      #[allow(unused_mut)]
      let mut out: [$type; CpuFeatureLevel::len()] = [$empty; CpuFeatureLevel::len()];

      // Can't use out[0][.] == $empty in static as of rust 1.40
      #[allow(unused_mut)]
      let mut set: [bool; CpuFeatureLevel::len()] = [false; CpuFeatureLevel::len()];

      #[allow(unused_imports)]
      use CpuFeatureLevel::*;
      $(
        out[$key as usize] = $value;
        set[$key as usize] = true;
      )*
      cpu_function_lookup_table!(waterfall_cpu_features(out, set, [SSE2, SSSE3, SSE4_1, AVX2, AVX512, AVX512ICL]));
      out
    };
  };

  // Fill empty output functions with the existent functions they support.
  // cpus should be in order of lowest cpu level to highest
  // Used like an internal function
  // Put in here to avoid adding more public macros
  (waterfall_cpu_features($out:ident, $set:ident, [$($cpu:ident),*])) => {
    // Use an array to emulate if statements (not supported in static as of
    // rust 1.40). Setting best[0] (false) and best[1] (true) is equivalent to
    // doing nothing and overriding our value respectively.
    #[allow(unused_assignments)]
    let mut best = [$out[0], $out[0]];
    $(
      // If the current entry has a function, update out best function.
      best[$set[$cpu as usize] as usize] = $out[$cpu as usize];
      // Update our current entry. Does nothing if it already had a function.
      $out[$cpu as usize] = best[1];
    )*
  };

  // version for default visibility
  ($name:ident: [$type:ty], default: $empty:expr, [$(($key:ident, $value:expr)),*]) => {
    cpu_function_lookup_table!(pub(self), $name: [$type], default: $empty, [$(($key, $value)),*]);
  };

  // use $name_$key as our values
  ($pub:vis, $name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
    paste::item!{
      cpu_function_lookup_table!(
        $pub, $name: [$type], default: $empty, [$(($key, [<$name _$key>])),*]
      );
    }
  };

  // version for default visibility
  ($name:ident: [$type:ty], default: $empty:expr, [$($key:ident),*]) => {
    cpu_function_lookup_table!(
      pub(self), $name: [$type], default: $empty, [$($key),*]
    );
  };
}
<|endoftext|>


<commit_before>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath,
                  ConfigOptPkgIdent,
                  ConfigOptRemoteSup,
                  PkgIdent,
                  RemoteSup};
use configopt::{configopt_fields,
                ConfigOpt};
use habitat_core::{os::process::ShutdownTimeout,
                   package::PackageIdent,
                   service::{HealthCheckInterval,
                             ServiceGroup}};
use habitat_sup_protocol::types::UpdateCondition;
use structopt::StructOpt;
use url::Url;

/// Commands relating to Habitat services
#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
#[allow(clippy::large_enum_variant)]
pub enum Svc {
    Key(Key),
    /// Load a service to be started and supervised by Habitat from a package identifier. If an
    /// installed package doesn't satisfy the given package identifier, a suitable package will be
    /// installed from Builder.
    #[structopt(no_version)]
    Load(Load),
    /// Start a loaded, but stopped, Habitat service.
    Start {
        #[structopt(flatten)]
        pkg_ident:  PkgIdent,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Query the status of Habitat services
    Status {
        /// A package identifier (ex: core/redis, core/busybox-static/1.42.2)
        #[structopt(name = "PKG_IDENT")]
        pkg_ident:  Option<PackageIdent>,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Stop a running Habitat service.
    Stop {
        #[structopt(flatten)]
        pkg_ident:        PkgIdent,
        #[structopt(flatten)]
        remote_sup:       RemoteSup,
        /// The number of seconds after sending a shutdown signal to wait before killing a service
        /// process (default: set in plan)
        #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
        shutdown_timeout: Option<ShutdownTimeout>,
    },
    /// Unload a service loaded by the Habitat Supervisor. If the service is running it will
    /// additionally be stopped.
    Unload {
        #[structopt(flatten)]
        pkg_ident:        PkgIdent,
        #[structopt(flatten)]
        remote_sup:       RemoteSup,
        /// The number of seconds after sending a shutdown signal to wait before killing a service
        /// process (default: set in plan)
        #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
        shutdown_timeout: Option<ShutdownTimeout>,
    },
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat service keys
pub enum Key {
    /// Generates a Habitat service key
    Generate {
        /// Target service group service.group[@organization] (ex: redis.default or
        /// foo.default@bazcorp)
        #[structopt(name = "SERVICE_GROUP")]
        service_group:  ServiceGroup,
        /// The service organization
        #[structopt(name = "ORG")]
        org:            Option<String>,
        #[structopt(flatten)]
        cache_key_path: CacheKeyPath,
    },
}

#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[serde(deny_unknown_fields)]
#[structopt(no_version)]
#[allow(dead_code)]
pub struct SharedLoad {
    /// Receive updates from the specified release channel
    #[structopt(name = "CHANNEL", long = "channel", default_value = "stable")]
    channel:               String,
    /// Specify an alternate Builder endpoint. If not specified, the value will be taken from
    /// the HAB_BLDR_URL environment variable if defined. (default: https://bldr.habitat.sh)
    // TODO (DM): This should probably use `env` and `default_value`
    // TODO (DM): Nested flattens do no work
    #[structopt(name = "BLDR_URL", short = "u", long = "url")]
    bldr_url:              Option<Url>,
    /// The service group; shared config and topology [default: default]
    // TODO (DM): This should set a default value
    #[structopt(name = "GROUP", long = "group")]
    group:                 Option<String>,
    /// Service topology; [default: none]
    // TODO (DM): I dont think saying the default is none makes sense here
    #[structopt(name = "TOPOLOGY",
            long = "topology",
            short = "t",
            possible_values = &["standalone", "leader"])]
    topology:              Option<habitat_sup_protocol::types::Topology>,
    /// The update strategy; [default: none] [values: none, at-once, rolling]
    // TODO (DM): this should set a default_value and use possible_values = &["none", "at-once",
    // "rolling"]
    #[structopt(name = "STRATEGY", long = "strategy", short = "s")]
    strategy:              Option<habitat_sup_protocol::types::UpdateStrategy>,
    /// The condition dictating when this service should update
    ///
    /// latest: Runs the latest package that can be found in the configured channel and local
    /// packages.
    ///
    /// track-channel: Always run what is at the head of a given channel. This enables service
    /// rollback where demoting a package from a channel will cause the package to rollback to
    /// an older version of the package. A ramification of enabling this condition is packages
    /// newer than the package at the head of the channel will be automatically uninstalled
    /// during a service rollback.
    #[structopt(name = "UPDATE_CONDITION",
                long = "update-condition",
                default_value = UpdateCondition::Latest.as_str(),
                possible_values = UpdateCondition::VARIANTS)]
    update_condition:      UpdateCondition,
    /// One or more service groups to bind to a configuration
    #[structopt(name = "BIND", long = "bind")]
    #[serde(default)]
    bind:                  Vec<String>,
    /// Governs how the presence or absence of binds affects service startup. `strict` blocks
    /// startup until all binds are present. [default: strict] [values: relaxed, strict]
    // TODO (DM): This should set default_value and use possible_values
    #[structopt(name = "BINDING_MODE", long = "binding-mode")]
    binding_mode:          Option<habitat_sup_protocol::types::BindingMode>,
    /// The interval (seconds) on which to run health checks [default: 30]
    // TODO (DM): Should use default_value = "30"
    #[structopt(name = "HEALTH_CHECK_INTERVAL",
                long = "health-check-interval",
                short = "i")]
    health_check_interval: Option<HealthCheckInterval>,
    /// The number of seconds after sending a shutdown signal to wait before killing a service
    /// process (default: set in plan)
    #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
    shutdown_timeout:      Option<ShutdownTimeout>,
    // TODO (DM): This flag can eventually be removed.
    // See https://github.com/habitat-sh/habitat/issues/7339
    /// DEPRECATED
    #[structopt(name = "APPLICATION",
                long = "application",
                short = "a",
                takes_value = false,
                hidden = true)]
    #[serde(skip)]
    application:           Vec<String>,
    // TODO (DM): This flag can eventually be removed.
    // See https://github.com/habitat-sh/habitat/issues/7339
    /// DEPRECATED
    #[structopt(name = "ENVIRONMENT",
                long = "environment",
                short = "e",
                takes_value = false,
                hidden = true)]
    #[serde(skip)]
    environment:           Vec<String>,
}

#[configopt_fields]
#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[serde(deny_unknown_fields)]
#[structopt(no_version)]
#[allow(dead_code)]
pub struct Load {
    #[structopt(flatten)]
    #[serde(flatten)]
    pkg_ident:   PkgIdent,
    /// Load or reload an already loaded service. If the service was previously loaded and
    /// running this operation will also restart the service
    #[structopt(name = "FORCE", short = "f", long = "force")]
    force:       bool,
    #[structopt(flatten)]
    #[serde(flatten)]
    remote_sup:  RemoteSup,
    #[cfg(target_os = "windows")]
    /// Password of the service user
    #[structopt(name = "PASSWORD", long = "password")]
    password:    Option<String>,
    #[structopt(flatten)]
    #[serde(flatten)]
    shared_load: SharedLoad,
}
<commit_msg>Remove config file for hab svc load<commit_after>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath,
                  ConfigOptPkgIdent,
                  ConfigOptRemoteSup,
                  PkgIdent,
                  RemoteSup};
use configopt::ConfigOpt;
use habitat_core::{os::process::ShutdownTimeout,
                   package::PackageIdent,
                   service::{HealthCheckInterval,
                             ServiceGroup}};
use habitat_sup_protocol::types::UpdateCondition;
use structopt::StructOpt;
use url::Url;

/// Commands relating to Habitat services
#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
#[allow(clippy::large_enum_variant)]
pub enum Svc {
    Key(Key),
    /// Load a service to be started and supervised by Habitat from a package identifier. If an
    /// installed package doesn't satisfy the given package identifier, a suitable package will be
    /// installed from Builder.
    #[structopt(no_version)]
    Load(Load),
    /// Start a loaded, but stopped, Habitat service.
    Start {
        #[structopt(flatten)]
        pkg_ident:  PkgIdent,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Query the status of Habitat services
    Status {
        /// A package identifier (ex: core/redis, core/busybox-static/1.42.2)
        #[structopt(name = "PKG_IDENT")]
        pkg_ident:  Option<PackageIdent>,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Stop a running Habitat service.
    Stop {
        #[structopt(flatten)]
        pkg_ident:        PkgIdent,
        #[structopt(flatten)]
        remote_sup:       RemoteSup,
        /// The number of seconds after sending a shutdown signal to wait before killing a service
        /// process (default: set in plan)
        #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
        shutdown_timeout: Option<ShutdownTimeout>,
    },
    /// Unload a service loaded by the Habitat Supervisor. If the service is running it will
    /// additionally be stopped.
    Unload {
        #[structopt(flatten)]
        pkg_ident:        PkgIdent,
        #[structopt(flatten)]
        remote_sup:       RemoteSup,
        /// The number of seconds after sending a shutdown signal to wait before killing a service
        /// process (default: set in plan)
        #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
        shutdown_timeout: Option<ShutdownTimeout>,
    },
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat service keys
pub enum Key {
    /// Generates a Habitat service key
    Generate {
        /// Target service group service.group[@organization] (ex: redis.default or
        /// foo.default@bazcorp)
        #[structopt(name = "SERVICE_GROUP")]
        service_group:  ServiceGroup,
        /// The service organization
        #[structopt(name = "ORG")]
        org:            Option<String>,
        #[structopt(flatten)]
        cache_key_path: CacheKeyPath,
    },
}

#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[serde(deny_unknown_fields)]
#[structopt(no_version)]
#[allow(dead_code)]
pub struct SharedLoad {
    /// Receive updates from the specified release channel
    #[structopt(name = "CHANNEL", long = "channel", default_value = "stable")]
    channel:               String,
    /// Specify an alternate Builder endpoint. If not specified, the value will be taken from
    /// the HAB_BLDR_URL environment variable if defined. (default: https://bldr.habitat.sh)
    // TODO (DM): This should probably use `env` and `default_value`
    // TODO (DM): Nested flattens do no work
    #[structopt(name = "BLDR_URL", short = "u", long = "url")]
    bldr_url:              Option<Url>,
    /// The service group; shared config and topology [default: default]
    // TODO (DM): This should set a default value
    #[structopt(name = "GROUP", long = "group")]
    group:                 Option<String>,
    /// Service topology; [default: none]
    // TODO (DM): I dont think saying the default is none makes sense here
    #[structopt(name = "TOPOLOGY",
            long = "topology",
            short = "t",
            possible_values = &["standalone", "leader"])]
    topology:              Option<habitat_sup_protocol::types::Topology>,
    /// The update strategy; [default: none] [values: none, at-once, rolling]
    // TODO (DM): this should set a default_value and use possible_values = &["none", "at-once",
    // "rolling"]
    #[structopt(name = "STRATEGY", long = "strategy", short = "s")]
    strategy:              Option<habitat_sup_protocol::types::UpdateStrategy>,
    /// The condition dictating when this service should update
    ///
    /// latest: Runs the latest package that can be found in the configured channel and local
    /// packages.
    ///
    /// track-channel: Always run what is at the head of a given channel. This enables service
    /// rollback where demoting a package from a channel will cause the package to rollback to
    /// an older version of the package. A ramification of enabling this condition is packages
    /// newer than the package at the head of the channel will be automatically uninstalled
    /// during a service rollback.
    #[structopt(name = "UPDATE_CONDITION",
                long = "update-condition",
                default_value = UpdateCondition::Latest.as_str(),
                possible_values = UpdateCondition::VARIANTS)]
    update_condition:      UpdateCondition,
    /// One or more service groups to bind to a configuration
    #[structopt(name = "BIND", long = "bind")]
    #[serde(default)]
    bind:                  Vec<String>,
    /// Governs how the presence or absence of binds affects service startup. `strict` blocks
    /// startup until all binds are present. [default: strict] [values: relaxed, strict]
    // TODO (DM): This should set default_value and use possible_values
    #[structopt(name = "BINDING_MODE", long = "binding-mode")]
    binding_mode:          Option<habitat_sup_protocol::types::BindingMode>,
    /// The interval (seconds) on which to run health checks [default: 30]
    // TODO (DM): Should use default_value = "30"
    #[structopt(name = "HEALTH_CHECK_INTERVAL",
                long = "health-check-interval",
                short = "i")]
    health_check_interval: Option<HealthCheckInterval>,
    /// The number of seconds after sending a shutdown signal to wait before killing a service
    /// process (default: set in plan)
    #[structopt(name = "SHUTDOWN_TIMEOUT", long = "shutdown-timeout")]
    shutdown_timeout:      Option<ShutdownTimeout>,
    // TODO (DM): This flag can eventually be removed.
    // See https://github.com/habitat-sh/habitat/issues/7339
    /// DEPRECATED
    #[structopt(name = "APPLICATION",
                long = "application",
                short = "a",
                takes_value = false,
                hidden = true)]
    #[serde(skip)]
    application:           Vec<String>,
    // TODO (DM): This flag can eventually be removed.
    // See https://github.com/habitat-sh/habitat/issues/7339
    /// DEPRECATED
    #[structopt(name = "ENVIRONMENT",
                long = "environment",
                short = "e",
                takes_value = false,
                hidden = true)]
    #[serde(skip)]
    environment:           Vec<String>,
}

#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[serde(deny_unknown_fields)]
#[structopt(no_version)]
#[allow(dead_code)]
pub struct Load {
    #[structopt(flatten)]
    #[serde(flatten)]
    pkg_ident:   PkgIdent,
    /// Load or reload an already loaded service. If the service was previously loaded and
    /// running this operation will also restart the service
    #[structopt(name = "FORCE", short = "f", long = "force")]
    force:       bool,
    #[structopt(flatten)]
    #[serde(flatten)]
    remote_sup:  RemoteSup,
    #[cfg(target_os = "windows")]
    /// Password of the service user
    #[structopt(name = "PASSWORD", long = "password")]
    password:    Option<String>,
    #[structopt(flatten)]
    #[serde(flatten)]
    shared_load: SharedLoad,
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cg;
use darling::util::Override;
use quote::Tokens;
use syn::{self, Ident};
use synstructure;

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    let s = synstructure::Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        let bindings = variant.bindings();
        let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
        let ast = variant.ast();
        let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
        let separator = if variant_attrs.comma { ", " } else { " " };

        if variant_attrs.dimension {
            assert_eq!(bindings.len(), 1);
            assert!(
                variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
                "That makes no sense"
            );
        }

        let mut expr = if let Some(keyword) = variant_attrs.keyword {
            assert!(bindings.is_empty());
            let keyword = keyword.to_string();
            quote! {
                ::std::fmt::Write::write_str(dest, #keyword)
            }
        } else if !bindings.is_empty() {
            let mut expr = quote! {};
            if variant_attrs.iterable {
                assert_eq!(bindings.len(), 1);
                let binding = &bindings[0];
                expr = quote! {
                    #expr

                    for item in #binding.iter() {
                        writer.item(&item)?;
                    }
                };
            } else {
                for binding in bindings {
                    let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
                    if attrs.skip {
                        continue;
                    }
                    if !attrs.ignore_bound {
                        where_clause.add_trait_bound(&binding.ast().ty);
                    }
                    expr = quote! {
                        #expr
                        writer.item(#binding)?;
                    };
                }
            }

            quote! {{
                let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
                #expr
                Ok(())
            }}
        } else {
            quote! {
                ::std::fmt::Write::write_str(dest, #identifier)
            }
        };

        if variant_attrs.dimension {
            expr = quote! {
                #expr?;
                ::std::fmt::Write::write_str(dest, #identifier)
            }
        } else if let Some(function) = variant_attrs.function {
            let mut identifier = function.explicit().map_or(identifier, |name| name.to_string());
            identifier.push_str("(");
            expr = quote! {
                ::std::fmt::Write::write_str(dest, #identifier)?;
                #expr?;
                ::std::fmt::Write::write_str(dest, ")")
            }
        }
        Some(expr)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<Ident>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
    // Here because structs variants are also their whole type definition.
    iterable: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<Ident>>,
    pub iterable: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    ignore_bound: bool,
    skip: bool,
}
<commit_msg>Extract variant code to its own function in style_derive::to_css<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::Tokens;
use syn::{self, Ident};
use synstructure::{Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        let keyword = keyword.to_string();
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        let mut expr = quote! {};
        if variant_attrs.iterable {
            assert_eq!(bindings.len(), 1);
            let binding = &bindings[0];
            expr = quote! {
                #expr

                for item in #binding.iter() {
                    writer.item(&item)?;
                }
            };
        } else {
            for binding in bindings {
                let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
                if attrs.skip {
                    continue;
                }
                if !attrs.ignore_bound {
                    where_clause.add_trait_bound(&binding.ast().ty);
                }
                expr = quote! {
                    #expr
                    writer.item(#binding)?;
                };
            }
        }

        quote! {{
            let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
            #expr
            Ok(())
        }}
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name.to_string());
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<Ident>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
    // Here because structs variants are also their whole type definition.
    iterable: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<Ident>>,
    pub iterable: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    ignore_bound: bool,
    skip: bool,
}
<|endoftext|>


<commit_before>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = i16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature --(unless repeated_mode)->
///                 Disconfigure
#[derive(Clone,Copy,PartialEq)]
enum ProtocolState {
    Idle,

    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register. Optionally contains the most recent
    /// temperature to give back to callbacks.
    Deconfigure(Option<f32>),

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(SensorVoltage),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: Cell<u8>,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: Cell::new(i2c_address),
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Idle),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Configure);
        });
    }

    fn disable_sensor(&self, temperature: Option<f32>) {
        // disable the TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x0000;
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Deconfigure(temperature));
        });
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }
}

fn calculate_temperature(sensor_voltage: i16, die_temperature: i16) -> f32 {
    // do calculation of actual temperature
    //  Calculations based on TMP006 User's Guide section 5.1
    let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
    let t_adj = t_die-T_REF;
    let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

    let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
    let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

    let v_adj = v_obj-v_os;
    let f_v_obj = v_adj + C_2*v_adj*v_adj;

    let t_kelvin =
        sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
    let t_celsius = t_kelvin + K_TO_C;

    // return data value
    t_celsius
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], _error: i2c::Error) {
        //TODO(alevy): handle protocol errors
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
            },
            ProtocolState::Deconfigure(temperature) => {
                self.buffer.replace(buffer);
                self.disable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
                temperature.map(|temp_val| {
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0));
                    self.callback.set(None);
                });
            },
            ProtocolState::SetRegSensorVoltage => {
                // Read sensor voltage register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(ProtocolState::ReadingSensorVoltage);
            },
            ProtocolState::ReadingSensorVoltage => {
                let sensor_voltage =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;

                // Select die temperature register
                buffer[0] = Registers::DieTemperature as u8;
                self.i2c.write(self.i2c_address.get(), buffer, 1);

                self.protocol_state.set(
                    ProtocolState::SetRegDieTemperature(sensor_voltage));
            },
            ProtocolState::SetRegDieTemperature(sensor_voltage) => {
                // Read die temperature register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(
                    ProtocolState::ReadingDieTemperature(sensor_voltage));
            },
            ProtocolState::ReadingDieTemperature(sensor_voltage) => {
                let die_temperature =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;
                self.buffer.replace(buffer);

                let temp_val = calculate_temperature(sensor_voltage, die_temperature);

                // disable callback and sensing if in single-shot mode
                if self.repeated_mode.get() == false {
                    // disable temperature sensor. When disabling is finished, we will give the
                    // temperature to the callback.
                    self.disable_sensor(Some(temp_val));
                } else {
                    // send value to callback
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0)
                    );

                    self.i2c.disable();
                }
            },
            _ => {}
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            // select sensor voltage register and read it
            buf[0] = Registers::SensorVoltage as u8;
            self.i2c.write(self.i2c_address.get(), buf, 1);
            self.protocol_state.set(ProtocolState::SetRegSensorVoltage);
        });
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor(None);

                0
            },

            // default
            _ => -1
        }
    }
}

<commit_msg>TMP006: Remove unnecessary Cell from struct<commit_after>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = i16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature --(unless repeated_mode)->
///                 Disconfigure
#[derive(Clone,Copy,PartialEq)]
enum ProtocolState {
    Idle,

    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register. Optionally contains the most recent
    /// temperature to give back to callbacks.
    Deconfigure(Option<f32>),

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(SensorVoltage),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: u8,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: i2c_address,
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Idle),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address, buf, 3);
            self.protocol_state.set(ProtocolState::Configure);
        });
    }

    fn disable_sensor(&self, temperature: Option<f32>) {
        // disable the TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x0000;
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address, buf, 3);
            self.protocol_state.set(ProtocolState::Deconfigure(temperature));
        });
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }
}

fn calculate_temperature(sensor_voltage: i16, die_temperature: i16) -> f32 {
    // do calculation of actual temperature
    //  Calculations based on TMP006 User's Guide section 5.1
    let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
    let t_adj = t_die-T_REF;
    let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

    let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
    let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

    let v_adj = v_obj-v_os;
    let f_v_obj = v_adj + C_2*v_adj*v_adj;

    let t_kelvin =
        sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
    let t_celsius = t_kelvin + K_TO_C;

    // return data value
    t_celsius
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], _error: i2c::Error) {
        //TODO(alevy): handle protocol errors
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
            },
            ProtocolState::Deconfigure(temperature) => {
                self.buffer.replace(buffer);
                self.disable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
                temperature.map(|temp_val| {
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0));
                    self.callback.set(None);
                });
            },
            ProtocolState::SetRegSensorVoltage => {
                // Read sensor voltage register
                self.i2c.read(self.i2c_address, buffer, 2);
                self.protocol_state.set(ProtocolState::ReadingSensorVoltage);
            },
            ProtocolState::ReadingSensorVoltage => {
                let sensor_voltage =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;

                // Select die temperature register
                buffer[0] = Registers::DieTemperature as u8;
                self.i2c.write(self.i2c_address, buffer, 1);

                self.protocol_state.set(
                    ProtocolState::SetRegDieTemperature(sensor_voltage));
            },
            ProtocolState::SetRegDieTemperature(sensor_voltage) => {
                // Read die temperature register
                self.i2c.read(self.i2c_address, buffer, 2);
                self.protocol_state.set(
                    ProtocolState::ReadingDieTemperature(sensor_voltage));
            },
            ProtocolState::ReadingDieTemperature(sensor_voltage) => {
                let die_temperature =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;
                self.buffer.replace(buffer);

                let temp_val = calculate_temperature(sensor_voltage, die_temperature);

                // disable callback and sensing if in single-shot mode
                if self.repeated_mode.get() == false {
                    // disable temperature sensor. When disabling is finished, we will give the
                    // temperature to the callback.
                    self.disable_sensor(Some(temp_val));
                } else {
                    // send value to callback
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0)
                    );

                    self.i2c.disable();
                }
            },
            _ => {}
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            // select sensor voltage register and read it
            buf[0] = Registers::SensorVoltage as u8;
            self.i2c.write(self.i2c_address, buf, 1);
            self.protocol_state.set(ProtocolState::SetRegSensorVoltage);
        });
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor(None);

                0
            },

            // default
            _ => -1
        }
    }
}

<|endoftext|>


<commit_before><commit_msg>macroize the FindMatch function<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards};
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::{offset_of_array_data, Obj};
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    large_space: &'a LargeSpace,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: ForwardTable,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: ForwardTable::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();
        self.update_large_objects();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!(
                "GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(garbage),
                garbage_ratio
            );
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();
        let mut live_objects = 0;

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                if !self.is_marked_addr(root_ptr) {
                    marking_stack.push(root_ptr);
                    self.mark(root_ptr);
                    live_objects += 1;
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                        live_objects += 1;
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }

        self.fwd_table.reserve_capacity(live_objects);
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.forward_to(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, _address, _| {
            if full.is_marked(object) {
                object.visit_reference_fields(|field| {
                    full.forward_reference(field);
                });
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr)
                && !self.large_space.contains(root_ptr)
            {
                let fwd_addr = self.fwd_table.forward_address(root_ptr);
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let dest = full.fwd_table.forward_address(address);
                object.copy_to(dest, object_size);

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(dest, next_dest, object.is_array_ref());
                }

                last_dest = next_dest;
            }
        });

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;
        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn update_large_objects(&mut self) {
        self.large_space.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                self.forward_reference(field);
            });
        });
    }

    fn forward_reference(&mut self, indirect_obj: IndirectObj) {
        let object_addr = Address::from_ptr(indirect_obj.get());

        if !object_addr.is_null() && !self.perm_space.contains(object_addr)
            && !self.large_space.contains(object_addr)
        {
            let fwd_addr = self.fwd_table.forward_address(object_addr);
            indirect_obj.set(fwd_addr.to_mut_ptr());
        }
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        assert!(self.old_top.is_null());
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, last: Address, addr: Address, array_ref: bool) {
        let last_card = self.old.card_from_address(last);

        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / mem::ptr_width_usize();

        let card = self.old.card_from_address(addr);

        if array_ref {
            let last_card_end = self.old.address_from_card(last_card).offset(CARD_SIZE);
            let loop_start;

            if last.offset(offset_of_array_data() as usize) > last_card_end {
                let diff_words = last_card_end.offset_from(last) / mem::ptr_width_usize();
                self.crossing_map
                    .set_array_start((last_card.to_usize() + 1).into(), diff_words);

                loop_start = last_card.to_usize() + 2;
            } else {
                loop_start = last_card.to_usize() + 1;
            }

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();

            for i in loop_start..card.to_usize() {
                self.crossing_map
                    .set_references_at_start(i.into(), refs_per_card);
            }

            if card.to_usize() >= loop_start {
                self.crossing_map
                    .set_references_at_start(card, offset_words);
            }
        } else {
            for i in last_card.to_usize() + 1..card.to_usize() {
                self.crossing_map.set_no_references(i.into());
            }

            self.crossing_map.set_first_object(card, offset_words);
        }
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap
            .is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe { *addr.to_ptr() }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}

struct ForwardTable {
    data: HashMap<Address, Address>,
}

impl ForwardTable {
    fn new() -> ForwardTable {
        ForwardTable {
            data: HashMap::new(),
        }
    }

    fn reserve_capacity(&mut self, count: usize) {
        self.data.reserve(count);
    }

    fn forward_to(&mut self, addr: Address, fwd: Address) {
        self.data.insert(addr, fwd);
    }

    fn forward_address(&mut self, addr: Address) -> Address {
        *self.data
            .get(&addr)
            .expect("no forward address found.")
    }
}
<commit_msg>swiper: all objects in old gen after full GC<commit_after>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards};
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::{offset_of_array_data, Obj};
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    large_space: &'a LargeSpace,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: ForwardTable,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: ForwardTable::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();
        self.update_large_objects();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!(
                "GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur),
                in_kilo(init_size),
                in_kilo(new_size),
                in_kilo(garbage),
                garbage_ratio
            );
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();
        let mut live_objects = 0;

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                if !self.is_marked_addr(root_ptr) {
                    marking_stack.push(root_ptr);
                    self.mark(root_ptr);
                    live_objects += 1;
                }
            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                        live_objects += 1;
                    }
                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }

        self.fwd_table.reserve_capacity(live_objects);
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.forward_to(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, _address, _| {
            if full.is_marked(object) {
                object.visit_reference_fields(|field| {
                    full.forward_reference(field);
                });
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr)
                && !self.large_space.contains(root_ptr)
            {
                let fwd_addr = self.fwd_table.forward_address(root_ptr);
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let dest = full.fwd_table.forward_address(address);
                object.copy_to(dest, object_size);

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(dest, next_dest, object.is_array_ref());
                }

                last_dest = next_dest;
            }
        });

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;
        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn update_large_objects(&mut self) {
        self.large_space.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|field| {
                self.forward_reference(field);
            });
        });
    }

    fn forward_reference(&mut self, indirect_obj: IndirectObj) {
        let object_addr = Address::from_ptr(indirect_obj.get());

        if !object_addr.is_null() && !self.perm_space.contains(object_addr)
            && !self.large_space.contains(object_addr)
        {
            let fwd_addr = self.fwd_table.forward_address(object_addr);
            indirect_obj.set(fwd_addr.to_mut_ptr());
        }
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F)
    where
        F: FnMut(&mut FullCollector, &mut Obj, Address, usize),
    {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        panic!("FAIL: Not enough space for objects in old generation.");
    }

    fn update_crossing(&mut self, last: Address, addr: Address, array_ref: bool) {
        let last_card = self.old.card_from_address(last);

        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / mem::ptr_width_usize();

        let card = self.old.card_from_address(addr);

        if array_ref {
            let last_card_end = self.old.address_from_card(last_card).offset(CARD_SIZE);
            let loop_start;

            if last.offset(offset_of_array_data() as usize) > last_card_end {
                let diff_words = last_card_end.offset_from(last) / mem::ptr_width_usize();
                self.crossing_map
                    .set_array_start((last_card.to_usize() + 1).into(), diff_words);

                loop_start = last_card.to_usize() + 2;
            } else {
                loop_start = last_card.to_usize() + 1;
            }

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();

            for i in loop_start..card.to_usize() {
                self.crossing_map
                    .set_references_at_start(i.into(), refs_per_card);
            }

            if card.to_usize() >= loop_start {
                self.crossing_map
                    .set_references_at_start(card, offset_words);
            }
        } else {
            for i in last_card.to_usize() + 1..card.to_usize() {
                self.crossing_map.set_no_references(i.into());
            }

            self.crossing_map.set_first_object(card, offset_words);
        }
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap
            .is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe { *addr.to_ptr() }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}

struct ForwardTable {
    data: HashMap<Address, Address>,
}

impl ForwardTable {
    fn new() -> ForwardTable {
        ForwardTable {
            data: HashMap::new(),
        }
    }

    fn reserve_capacity(&mut self, count: usize) {
        self.data.reserve(count);
    }

    fn forward_to(&mut self, addr: Address, fwd: Address) {
        self.data.insert(addr, fwd);
    }

    fn forward_address(&mut self, addr: Address) -> Address {
        *self.data
            .get(&addr)
            .expect("no forward address found.")
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use super::P2d;

pub struct SvgCanvas {
    pub width: f32,
    pub height: f32,
    pub border: f32,
    pub radius: f32,
    pub scalex: f32,
    pub scaley: f32,
    pub offsetx: f32,
    pub offsety: f32,
    pub stroke_width: f32,
    pub stroke_color: String,
    pub fill_color: String,
}

impl SvgCanvas {
    /// If all graph coordinates are in [0,1].
    pub fn default_for_unit_layout() -> SvgCanvas {
        SvgCanvas{
            width:1000.0,
            height:1000.0,
            border: 40.0,
            radius: 10.0,
            scalex: 1000.0,
            scaley: 1000.0,
            offsetx: 0.0,
            offsety: 0.0,
            stroke_width: 1.0,
            stroke_color: "black".to_string(),
            fill_color: "red".to_string(),
        }
    }
}

pub struct SvgWriter<'a> {
    canvas: SvgCanvas,
    wr: &'a mut Write,
}

impl<'a> SvgWriter<'a> {
    pub fn new<'b>(canvas: SvgCanvas, wr: &'b mut Write) -> SvgWriter<'b> {
        SvgWriter{canvas: canvas, wr: wr}
    }

    pub fn header(&mut self) {
        writeln!(&mut self.wr, r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                width="100%" height="100%"
                viewBox="{} {} {} {}">"#, 0, 0, self.canvas.width+2.0*self.canvas.border, self.canvas.height+2.0*self.canvas.border).unwrap();
        writeln!(&mut self.wr, r##"
                <defs>
                <marker id="arrow" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto"
                markerWidth="8" markerHeight="6"><polyline points="0,0 10,5 0,10 1,5" fill="darkblue" /></marker>
                </defs>"##).unwrap();
    }

    pub fn footer(&mut self) {
        writeln!(&mut self.wr, "</svg>").unwrap();
    }

    pub fn node(&mut self, pos: &P2d) {
        let x = self.canvas.border + (pos.0*self.canvas.scalex) + self.canvas.offsetx;
        let y = self.canvas.border + (pos.1*self.canvas.scaley) + self.canvas.offsety;
        writeln!(&mut self.wr, r#"<circle cx="{}" cy="{}" r="{}" stroke="{}" stroke-width="{}px" fill="{}" />"#,
                 x, y, self.canvas.radius, self.canvas.stroke_color, self.canvas.stroke_width, self.canvas.fill_color).unwrap();
    }

    pub fn edge(&mut self, pos1: &P2d, pos2: &P2d, directed: bool) {
        let x1 = self.canvas.border + (pos1.0*self.canvas.scalex) + self.canvas.offsetx;
        let y1 = self.canvas.border + (pos1.1*self.canvas.scaley) + self.canvas.offsety;
        let x2 = self.canvas.border + (pos2.0*self.canvas.scalex) + self.canvas.offsetx;
        let y2 = self.canvas.border + (pos2.1*self.canvas.scaley) + self.canvas.offsety;

        let dx = x2 - x1;
        let dy = y2 - y1;

        let mx = x1 + 0.5 * dx;
        let my = y1 + 0.5 * dy;

        let marker = if directed {
            r##" marker-mid="url(#arrow)""##
        } else {
            ""
        };

        writeln!(&mut self.wr, r#"<path d="M{} {} L{} {} L{} {}" stroke="{}" stroke-width="{}px" {}/>"#,
                 x1, y1, mx, my, x2, y2, self.canvas.stroke_color, self.canvas.stroke_width, marker).unwrap();
    }

    pub fn draw_graph(mut self, node_positions: &Vec<P2d>, node_neighbors: &Vec<Vec<usize>>, directed: bool) {
        self.header();

        // start with the edges
        for (i, pos1) in node_positions.iter().enumerate() {
            for &n in node_neighbors[i].iter() {
                let pos2 = &node_positions[n];
                self.edge(&pos1, &pos2, directed);
            }
        }

        // then with the nodes.
        for pos1 in node_positions.iter() {
            self.node(&pos1);
        }

        self.footer();
    }
}
<commit_msg>Don't draw an edge if both endpoints are too close together.<commit_after>use std::io::Write;
use super::P2d;

pub struct SvgCanvas {
    pub width: f32,
    pub height: f32,
    pub border: f32,
    pub radius: f32,
    pub scalex: f32,
    pub scaley: f32,
    pub offsetx: f32,
    pub offsety: f32,
    pub stroke_width: f32,
    pub stroke_color: String,
    pub fill_color: String,
}

impl SvgCanvas {
    /// If all graph coordinates are in [0,1].
    pub fn default_for_unit_layout() -> SvgCanvas {
        SvgCanvas{
            width:1000.0,
            height:1000.0,
            border: 40.0,
            radius: 10.0,
            scalex: 1000.0,
            scaley: 1000.0,
            offsetx: 0.0,
            offsety: 0.0,
            stroke_width: 1.0,
            stroke_color: "black".to_string(),
            fill_color: "red".to_string(),
        }
    }
}

pub struct SvgWriter<'a> {
    canvas: SvgCanvas,
    wr: &'a mut Write,
}

impl<'a> SvgWriter<'a> {
    pub fn new<'b>(canvas: SvgCanvas, wr: &'b mut Write) -> SvgWriter<'b> {
        SvgWriter{canvas: canvas, wr: wr}
    }

    pub fn header(&mut self) {
        writeln!(&mut self.wr, r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                width="100%" height="100%"
                viewBox="{} {} {} {}">"#, 0, 0, self.canvas.width+2.0*self.canvas.border, self.canvas.height+2.0*self.canvas.border).unwrap();
        writeln!(&mut self.wr, r##"
                <defs>
                <marker id="arrow" viewBox="0 0 10 10" refX="1" refY="5" markerUnits="strokeWidth" orient="auto"
                markerWidth="8" markerHeight="6"><polyline points="0,0 10,5 0,10 1,5" fill="darkblue" /></marker>
                </defs>"##).unwrap();
    }

    pub fn footer(&mut self) {
        writeln!(&mut self.wr, "</svg>").unwrap();
    }

    pub fn node(&mut self, pos: &P2d) {
        let x = self.canvas.border + (pos.0*self.canvas.scalex) + self.canvas.offsetx;
        let y = self.canvas.border + (pos.1*self.canvas.scaley) + self.canvas.offsety;
        writeln!(&mut self.wr, r#"<circle cx="{}" cy="{}" r="{}" stroke="{}" stroke-width="{}px" fill="{}" />"#,
                 x, y, self.canvas.radius, self.canvas.stroke_color, self.canvas.stroke_width, self.canvas.fill_color).unwrap();
    }

    pub fn edge(&mut self, pos1: &P2d, pos2: &P2d, directed: bool) {
        let x1 = self.canvas.border + (pos1.0*self.canvas.scalex) + self.canvas.offsetx;
        let y1 = self.canvas.border + (pos1.1*self.canvas.scaley) + self.canvas.offsety;
        let x2 = self.canvas.border + (pos2.0*self.canvas.scalex) + self.canvas.offsetx;
        let y2 = self.canvas.border + (pos2.1*self.canvas.scaley) + self.canvas.offsety;

        let dx = x2 - x1;
        let dy = y2 - y1;

        if dx.abs() < 1.0/self.canvas.width && dy.abs() < 1.0/self.canvas.height {
            return;
        }

        let mx = x1 + 0.5 * dx;
        let my = y1 + 0.5 * dy;

        let marker = if directed {
            r##" marker-mid="url(#arrow)""##
        } else {
            ""
        };

        writeln!(&mut self.wr, r#"<path d="M{} {} L{} {} L{} {}" stroke="{}" stroke-width="{}px" {}/>"#,
                 x1, y1, mx, my, x2, y2, self.canvas.stroke_color, self.canvas.stroke_width, marker).unwrap();
    }

    pub fn draw_graph(mut self, node_positions: &Vec<P2d>, node_neighbors: &Vec<Vec<usize>>, directed: bool) {
        self.header();

        // start with the edges
        for (i, pos1) in node_positions.iter().enumerate() {
            for &n in node_neighbors[i].iter() {
                let pos2 = &node_positions[n];
                self.edge(&pos1, &pos2, directed);
            }
        }

        // then with the nodes.
        for pos1 in node_positions.iter() {
            self.node(&pos1);
        }

        self.footer();
    }
}
<|endoftext|>


<commit_before>const NUM_BYTES: usize = 4096;
const NUM_REGISTERS: usize = 16;
const STACK_SIZE: usize = 48;

pub struct System {
    memory: [u8; NUM_BYTES],
    registers: [u8; NUM_REGISTERS],
    pc: u16,
    index: u16,
    stack: [u8; STACK_SIZE],
    sp: u8
}

impl System{
    pub fn new() -> Self {
        System {
            memory: [0; NUM_BYTES],
            registers: [0; NUM_REGISTERS],
            pc: 0,
            index: 0,
            stack: [0; STACK_SIZE],
            sp: 0
        }
    }

    pub fn read_word(&self, address: usize) -> &[u8] {
        &self.memory[address..address + 2]
    }
}

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

    /** Load some test data into the system memory for the purposes of testing. */
    fn load_test_data(system: &mut System) {
        system.memory[0] = 0xAF;
        system.memory[1] = 0x7F;
        system.memory[NUM_BYTES / 2] = 0x77;
        system.memory[NUM_BYTES / 2 + 1] = 0x88;
        system.memory[NUM_BYTES - 2] = 0x3A;
        system.memory[NUM_BYTES - 1] = 0x01;
    }

    /** Read a word (two bytes) from the system memory. */
    #[test]
    fn read_word() {
        let mut system = System::new();
        load_test_data(&mut system);
        assert_eq!([0xAF, 0x7F], system.read_word(0));
        assert_eq!([0x77, 0x88], system.read_word(NUM_BYTES / 2));
        assert_eq!([0x3A, 0x01], system.read_word(NUM_BYTES - 2));
    }
}
<commit_msg>get word, not reference to word<commit_after>const NUM_BYTES: usize = 4096;
const NUM_REGISTERS: usize = 16;
const STACK_SIZE: usize = 48;

#[allow(dead_code)]
pub struct System {
    memory: [u8; NUM_BYTES],
    registers: [u8; NUM_REGISTERS],
    pc: u16,
    index: u16,
    stack: [u8; STACK_SIZE],
    sp: u8
}

#[allow(dead_code)]
impl System{
    pub fn new() -> Self {
        System {
            memory: [0; NUM_BYTES],
            registers: [0; NUM_REGISTERS],
            pc: 0,
            index: 0,
            stack: [0; STACK_SIZE],
            sp: 0
        }
    }

    /** Index into system memory at address and return word located there. */
    pub fn read_word(&self, address: usize) -> u16 {
        let left = self.memory[address] as u16;
        let right = self.memory[address + 1] as u16;
        (left << 8) | right
    }
}

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

    /** Load some test data into the system memory for the purposes of testing. */
    fn load_test_data(system: &mut System) {
        system.memory[0] = 0xAF;
        system.memory[1] = 0x7F;
        system.memory[NUM_BYTES / 2] = 0x77;
        system.memory[NUM_BYTES / 2 + 1] = 0x88;
        system.memory[NUM_BYTES - 2] = 0x3A;
        system.memory[NUM_BYTES - 1] = 0x01;
    }

    /** Read a word (two bytes) from the system memory. */
    #[test]
    fn read_word() {
        let mut system = System::new();
        load_test_data(&mut system);
        assert_eq!(0xAF7F, system.read_word(0));
        assert_eq!(0x7788, system.read_word(NUM_BYTES / 2));
        assert_eq!(0x3A01, system.read_word(NUM_BYTES - 2));
    }
}
<|endoftext|>