<commit_before>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::i32;

use super::Result;
use grpcio::CompressionAlgorithms;

use engine::rocks::util::io_limiter::DEFAULT_SNAP_MAX_BYTES_PER_SEC;
use tikv_util::collections::HashMap;
use tikv_util::config::{self, ReadableDuration, ReadableSize};

pub use crate::raftstore::store::Config as RaftStoreConfig;
pub use crate::storage::Config as StorageConfig;

pub const DEFAULT_CLUSTER_ID: u64 = 0;
pub const DEFAULT_LISTENING_ADDR: &str = "127.0.0.1:20160";
const DEFAULT_ADVERTISE_LISTENING_ADDR: &str = "";
const DEFAULT_STATUS_ADDR: &str = "127.0.0.1:20180";
const DEFAULT_GRPC_CONCURRENCY: usize = 4;
const DEFAULT_GRPC_CONCURRENT_STREAM: i32 = 1024;
const DEFAULT_GRPC_RAFT_CONN_NUM: usize = 1;
const DEFAULT_GRPC_STREAM_INITIAL_WINDOW_SIZE: u64 = 2 * 1024 * 1024;

// Number of rows in each chunk.
const DEFAULT_ENDPOINT_BATCH_ROW_LIMIT: usize = 64;

// If a request has been handled for more than 60 seconds, the client should
// be timeout already, so it can be safely aborted.
const DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS: u64 = 60;

// Number of rows in each chunk for streaming coprocessor.
const DEFAULT_ENDPOINT_STREAM_BATCH_ROW_LIMIT: usize = 128;

/// A clone of `grpc::CompressionAlgorithms` with serde supports.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GrpcCompressionType {
    None,
    Deflate,
    Gzip,
}

/// Configuration for the `server` module.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(default)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "kebab-case")]
pub struct Config {
    #[serde(skip)]
    pub cluster_id: u64,

    // Server listening address.
    pub addr: String,

    // Server advertise listening address for outer communication.
    // If not set, we will use listening address instead.
    pub advertise_addr: String,

    // These are related to TiKV status.
    pub status_addr: String,
    pub status_thread_pool_size: usize,

    // TODO: use CompressionAlgorithms instead once it supports traits like Clone etc.
    pub grpc_compression_type: GrpcCompressionType,
    pub grpc_concurrency: usize,
    pub grpc_concurrent_stream: i32,
    pub grpc_raft_conn_num: usize,
    pub grpc_stream_initial_window_size: ReadableSize,
    pub grpc_keepalive_time: ReadableDuration,
    pub grpc_keepalive_timeout: ReadableDuration,
    /// How many snapshots can be sent concurrently.
    pub concurrent_send_snap_limit: usize,
    /// How many snapshots can be recv concurrently.
    pub concurrent_recv_snap_limit: usize,
    pub end_point_recursion_limit: u32,
    pub end_point_stream_channel_size: usize,
    pub end_point_batch_row_limit: usize,
    pub end_point_stream_batch_row_limit: usize,
    pub end_point_enable_batch_if_possible: bool,
    pub end_point_request_max_handle_duration: ReadableDuration,
    pub snap_max_write_bytes_per_sec: ReadableSize,
    pub snap_max_total_size: ReadableSize,
    pub stats_concurrency: usize,
    pub heavy_load_threshold: usize,
    pub heavy_load_wait_duration: ReadableDuration,

    // Server labels to specify some attributes about this server.
    pub labels: HashMap<String, String>,

    // deprecated. use readpool.coprocessor.xx_concurrency.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_concurrency: Option<usize>,

    // deprecated. use readpool.coprocessor.stack_size.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_stack_size: Option<ReadableSize>,

    // deprecated. use readpool.coprocessor.max_tasks_per_worker_xx.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_max_tasks: Option<usize>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            cluster_id: DEFAULT_CLUSTER_ID,
            addr: DEFAULT_LISTENING_ADDR.to_owned(),
            labels: HashMap::default(),
            advertise_addr: DEFAULT_ADVERTISE_LISTENING_ADDR.to_owned(),
            status_addr: DEFAULT_STATUS_ADDR.to_owned(),
            status_thread_pool_size: 1,
            grpc_compression_type: GrpcCompressionType::None,
            grpc_concurrency: DEFAULT_GRPC_CONCURRENCY,
            grpc_concurrent_stream: DEFAULT_GRPC_CONCURRENT_STREAM,
            grpc_raft_conn_num: DEFAULT_GRPC_RAFT_CONN_NUM,
            grpc_stream_initial_window_size: ReadableSize(DEFAULT_GRPC_STREAM_INITIAL_WINDOW_SIZE),
            // There will be a heartbeat every secs, it's weird a connection will be idle for more
            // than 10 senconds.
            grpc_keepalive_time: ReadableDuration::secs(10),
            grpc_keepalive_timeout: ReadableDuration::secs(3),
            concurrent_send_snap_limit: 32,
            concurrent_recv_snap_limit: 32,
            end_point_concurrency: None, // deprecated
            end_point_max_tasks: None,   // deprecated
            end_point_stack_size: None,  // deprecated
            end_point_recursion_limit: 1000,
            end_point_stream_channel_size: 8,
            end_point_batch_row_limit: DEFAULT_ENDPOINT_BATCH_ROW_LIMIT,
            end_point_stream_batch_row_limit: DEFAULT_ENDPOINT_STREAM_BATCH_ROW_LIMIT,
            end_point_enable_batch_if_possible: true,
            end_point_request_max_handle_duration: ReadableDuration::secs(
                DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS,
            ),
            snap_max_write_bytes_per_sec: ReadableSize(DEFAULT_SNAP_MAX_BYTES_PER_SEC),
            snap_max_total_size: ReadableSize(0),
            stats_concurrency: 1,
            // 300 means gRPC threads are under heavy load if their total CPU usage
            // is greater than 300%.
            heavy_load_threshold: 300,
            // The resolution of timer in tokio is 1ms.
            heavy_load_wait_duration: ReadableDuration::millis(1),
        }
    }
}

impl Config {
    /// Validates the configuration and returns an error if it is misconfigured.
    pub fn validate(&mut self) -> Result<()> {
        box_try!(config::check_addr(&self.addr));
        if !self.advertise_addr.is_empty() {
            box_try!(config::check_addr(&self.advertise_addr));
        } else {
            info!(
                "no advertise-addr is specified, falling back to default addr";
                "addr" => %self.addr
            );
            self.advertise_addr = self.addr.clone();
        }
        if self.advertise_addr.starts_with("0.") {
            return Err(box_err!(
                "invalid advertise-addr: {:?}",
                self.advertise_addr
            ));
        }
        if !self.status_addr.is_empty() {
            box_try!(config::check_addr(&self.status_addr));
        }
        if self.status_addr == self.advertise_addr {
            return Err(box_err!(
                "status-addr has already been used: {:?}",
                self.advertise_addr
            ));
        }
        let non_zero_entries = vec![
            (
                "concurrent-send-snap-limit",
                self.concurrent_send_snap_limit,
            ),
            (
                "concurrent-recv-snap-limit",
                self.concurrent_recv_snap_limit,
            ),
        ];
        for (label, value) in non_zero_entries {
            if value == 0 {
                return Err(box_err!("server.{} should not be 0.", label));
            }
        }

        if self.end_point_recursion_limit < 100 {
            return Err(box_err!("server.end-point-recursion-limit is too small"));
        }

        if self.end_point_request_max_handle_duration.as_secs()
            < DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS
        {
            return Err(box_err!(
                "server.end-point-request-max-handle-secs is too small."
            ));
        }

        if self.grpc_stream_initial_window_size.0 > i32::MAX as u64 {
            return Err(box_err!(
                "server.grpc_stream_initial_window_size is too large."
            ));
        }

        for (k, v) in &self.labels {
            validate_label(k, "key")?;
            validate_label(v, "value")?;
        }

        Ok(())
    }

    /// Gets configured grpc compression algorithm.
    pub fn grpc_compression_algorithm(&self) -> CompressionAlgorithms {
        match self.grpc_compression_type {
            GrpcCompressionType::None => CompressionAlgorithms::GRPC_COMPRESS_NONE,
            GrpcCompressionType::Deflate => CompressionAlgorithms::GRPC_COMPRESS_DEFLATE,
            GrpcCompressionType::Gzip => CompressionAlgorithms::GRPC_COMPRESS_GZIP,
        }
    }
}

fn validate_label(s: &str, tp: &str) -> Result<()> {
    let report_err = || {
        box_err!(
            "store label {}: {:?} not match ^[a-zA-Z0-9]([a-zA-Z0-9-._]*[a-zA-Z0-9])?",
            tp,
            s
        )
    };
    if s.is_empty() {
        return Err(report_err());
    }
    let mut chrs = s.chars();
    let first_char = chrs.next().unwrap();
    if !first_char.is_ascii_alphanumeric() {
        return Err(report_err());
    }
    let last_char = match chrs.next_back() {
        None => return Ok(()),
        Some(c) => c,
    };
    if !last_char.is_ascii_alphanumeric() {
        return Err(report_err());
    }
    for c in chrs {
        if !c.is_ascii_alphanumeric() && !"-._".contains(c) {
            return Err(report_err());
        }
    }
    Ok(())
}

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

    #[test]
    fn test_config_validate() {
        let mut cfg = Config::default();
        assert!(cfg.advertise_addr.is_empty());
        cfg.validate().unwrap();
        assert_eq!(cfg.addr, cfg.advertise_addr);

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.concurrent_send_snap_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.concurrent_recv_snap_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.end_point_recursion_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.end_point_request_max_handle_duration = ReadableDuration::secs(0);
        assert!(invalid_cfg.validate().is_err());

        invalid_cfg = Config::default();
        invalid_cfg.addr = "0.0.0.0:1000".to_owned();
        assert!(invalid_cfg.validate().is_err());
        invalid_cfg.advertise_addr = "127.0.0.1:1000".to_owned();
        invalid_cfg.validate().unwrap();

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.advertise_addr = "127.0.0.1:1000".to_owned();
        invalid_cfg.status_addr = "127.0.0.1:1000".to_owned();
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.grpc_stream_initial_window_size = ReadableSize(i32::MAX as u64 + 1);
        assert!(invalid_cfg.validate().is_err());

        cfg.labels.insert("k1".to_owned(), "v1".to_owned());
        cfg.validate().unwrap();
        cfg.labels.insert("k2".to_owned(), "v2?".to_owned());
        assert!(cfg.validate().is_err());
    }

    #[test]
    fn test_store_labels() {
        let invalid_cases = vec!["", "123*", ".123", "💖"];

        for case in invalid_cases {
            assert!(validate_label(case, "dummy").is_err());
        }

        let valid_cases = vec![
            "a", "0", "a.1-2", "Cab", "abC", "b_1.2", "cab-012", "3ac.8b2",
        ];

        for case in valid_cases {
            validate_label(case, "dummy").unwrap();
        }
    }
}
<commit_msg>Check for 0.0.0.0 over 0. in advertise addr. (#5274)<commit_after>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use std::i32;

use super::Result;
use grpcio::CompressionAlgorithms;

use engine::rocks::util::io_limiter::DEFAULT_SNAP_MAX_BYTES_PER_SEC;
use tikv_util::collections::HashMap;
use tikv_util::config::{self, ReadableDuration, ReadableSize};

pub use crate::raftstore::store::Config as RaftStoreConfig;
pub use crate::storage::Config as StorageConfig;

pub const DEFAULT_CLUSTER_ID: u64 = 0;
pub const DEFAULT_LISTENING_ADDR: &str = "127.0.0.1:20160";
const DEFAULT_ADVERTISE_LISTENING_ADDR: &str = "";
const DEFAULT_STATUS_ADDR: &str = "127.0.0.1:20180";
const DEFAULT_GRPC_CONCURRENCY: usize = 4;
const DEFAULT_GRPC_CONCURRENT_STREAM: i32 = 1024;
const DEFAULT_GRPC_RAFT_CONN_NUM: usize = 1;
const DEFAULT_GRPC_STREAM_INITIAL_WINDOW_SIZE: u64 = 2 * 1024 * 1024;

// Number of rows in each chunk.
const DEFAULT_ENDPOINT_BATCH_ROW_LIMIT: usize = 64;

// If a request has been handled for more than 60 seconds, the client should
// be timeout already, so it can be safely aborted.
const DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS: u64 = 60;

// Number of rows in each chunk for streaming coprocessor.
const DEFAULT_ENDPOINT_STREAM_BATCH_ROW_LIMIT: usize = 128;

/// A clone of `grpc::CompressionAlgorithms` with serde supports.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GrpcCompressionType {
    None,
    Deflate,
    Gzip,
}

/// Configuration for the `server` module.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(default)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "kebab-case")]
pub struct Config {
    #[serde(skip)]
    pub cluster_id: u64,

    // Server listening address.
    pub addr: String,

    // Server advertise listening address for outer communication.
    // If not set, we will use listening address instead.
    pub advertise_addr: String,

    // These are related to TiKV status.
    pub status_addr: String,
    pub status_thread_pool_size: usize,

    // TODO: use CompressionAlgorithms instead once it supports traits like Clone etc.
    pub grpc_compression_type: GrpcCompressionType,
    pub grpc_concurrency: usize,
    pub grpc_concurrent_stream: i32,
    pub grpc_raft_conn_num: usize,
    pub grpc_stream_initial_window_size: ReadableSize,
    pub grpc_keepalive_time: ReadableDuration,
    pub grpc_keepalive_timeout: ReadableDuration,
    /// How many snapshots can be sent concurrently.
    pub concurrent_send_snap_limit: usize,
    /// How many snapshots can be recv concurrently.
    pub concurrent_recv_snap_limit: usize,
    pub end_point_recursion_limit: u32,
    pub end_point_stream_channel_size: usize,
    pub end_point_batch_row_limit: usize,
    pub end_point_stream_batch_row_limit: usize,
    pub end_point_enable_batch_if_possible: bool,
    pub end_point_request_max_handle_duration: ReadableDuration,
    pub snap_max_write_bytes_per_sec: ReadableSize,
    pub snap_max_total_size: ReadableSize,
    pub stats_concurrency: usize,
    pub heavy_load_threshold: usize,
    pub heavy_load_wait_duration: ReadableDuration,

    // Server labels to specify some attributes about this server.
    pub labels: HashMap<String, String>,

    // deprecated. use readpool.coprocessor.xx_concurrency.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_concurrency: Option<usize>,

    // deprecated. use readpool.coprocessor.stack_size.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_stack_size: Option<ReadableSize>,

    // deprecated. use readpool.coprocessor.max_tasks_per_worker_xx.
    #[doc(hidden)]
    #[serde(skip_serializing)]
    pub end_point_max_tasks: Option<usize>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            cluster_id: DEFAULT_CLUSTER_ID,
            addr: DEFAULT_LISTENING_ADDR.to_owned(),
            labels: HashMap::default(),
            advertise_addr: DEFAULT_ADVERTISE_LISTENING_ADDR.to_owned(),
            status_addr: DEFAULT_STATUS_ADDR.to_owned(),
            status_thread_pool_size: 1,
            grpc_compression_type: GrpcCompressionType::None,
            grpc_concurrency: DEFAULT_GRPC_CONCURRENCY,
            grpc_concurrent_stream: DEFAULT_GRPC_CONCURRENT_STREAM,
            grpc_raft_conn_num: DEFAULT_GRPC_RAFT_CONN_NUM,
            grpc_stream_initial_window_size: ReadableSize(DEFAULT_GRPC_STREAM_INITIAL_WINDOW_SIZE),
            // There will be a heartbeat every secs, it's weird a connection will be idle for more
            // than 10 senconds.
            grpc_keepalive_time: ReadableDuration::secs(10),
            grpc_keepalive_timeout: ReadableDuration::secs(3),
            concurrent_send_snap_limit: 32,
            concurrent_recv_snap_limit: 32,
            end_point_concurrency: None, // deprecated
            end_point_max_tasks: None,   // deprecated
            end_point_stack_size: None,  // deprecated
            end_point_recursion_limit: 1000,
            end_point_stream_channel_size: 8,
            end_point_batch_row_limit: DEFAULT_ENDPOINT_BATCH_ROW_LIMIT,
            end_point_stream_batch_row_limit: DEFAULT_ENDPOINT_STREAM_BATCH_ROW_LIMIT,
            end_point_enable_batch_if_possible: true,
            end_point_request_max_handle_duration: ReadableDuration::secs(
                DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS,
            ),
            snap_max_write_bytes_per_sec: ReadableSize(DEFAULT_SNAP_MAX_BYTES_PER_SEC),
            snap_max_total_size: ReadableSize(0),
            stats_concurrency: 1,
            // 300 means gRPC threads are under heavy load if their total CPU usage
            // is greater than 300%.
            heavy_load_threshold: 300,
            // The resolution of timer in tokio is 1ms.
            heavy_load_wait_duration: ReadableDuration::millis(1),
        }
    }
}

impl Config {
    /// Validates the configuration and returns an error if it is misconfigured.
    pub fn validate(&mut self) -> Result<()> {
        box_try!(config::check_addr(&self.addr));
        if !self.advertise_addr.is_empty() {
            box_try!(config::check_addr(&self.advertise_addr));
        } else {
            info!(
                "no advertise-addr is specified, falling back to default addr";
                "addr" => %self.addr
            );
            self.advertise_addr = self.addr.clone();
        }
        if self.advertise_addr.starts_with("0.0.0.0") {
            return Err(box_err!(
                "invalid advertise-addr: {:?}",
                self.advertise_addr
            ));
        }
        if !self.status_addr.is_empty() {
            box_try!(config::check_addr(&self.status_addr));
        }
        if self.status_addr == self.advertise_addr {
            return Err(box_err!(
                "status-addr has already been used: {:?}",
                self.advertise_addr
            ));
        }
        let non_zero_entries = vec![
            (
                "concurrent-send-snap-limit",
                self.concurrent_send_snap_limit,
            ),
            (
                "concurrent-recv-snap-limit",
                self.concurrent_recv_snap_limit,
            ),
        ];
        for (label, value) in non_zero_entries {
            if value == 0 {
                return Err(box_err!("server.{} should not be 0.", label));
            }
        }

        if self.end_point_recursion_limit < 100 {
            return Err(box_err!("server.end-point-recursion-limit is too small"));
        }

        if self.end_point_request_max_handle_duration.as_secs()
            < DEFAULT_ENDPOINT_REQUEST_MAX_HANDLE_SECS
        {
            return Err(box_err!(
                "server.end-point-request-max-handle-secs is too small."
            ));
        }

        if self.grpc_stream_initial_window_size.0 > i32::MAX as u64 {
            return Err(box_err!(
                "server.grpc_stream_initial_window_size is too large."
            ));
        }

        for (k, v) in &self.labels {
            validate_label(k, "key")?;
            validate_label(v, "value")?;
        }

        Ok(())
    }

    /// Gets configured grpc compression algorithm.
    pub fn grpc_compression_algorithm(&self) -> CompressionAlgorithms {
        match self.grpc_compression_type {
            GrpcCompressionType::None => CompressionAlgorithms::GRPC_COMPRESS_NONE,
            GrpcCompressionType::Deflate => CompressionAlgorithms::GRPC_COMPRESS_DEFLATE,
            GrpcCompressionType::Gzip => CompressionAlgorithms::GRPC_COMPRESS_GZIP,
        }
    }
}

fn validate_label(s: &str, tp: &str) -> Result<()> {
    let report_err = || {
        box_err!(
            "store label {}: {:?} not match ^[a-zA-Z0-9]([a-zA-Z0-9-._]*[a-zA-Z0-9])?",
            tp,
            s
        )
    };
    if s.is_empty() {
        return Err(report_err());
    }
    let mut chrs = s.chars();
    let first_char = chrs.next().unwrap();
    if !first_char.is_ascii_alphanumeric() {
        return Err(report_err());
    }
    let last_char = match chrs.next_back() {
        None => return Ok(()),
        Some(c) => c,
    };
    if !last_char.is_ascii_alphanumeric() {
        return Err(report_err());
    }
    for c in chrs {
        if !c.is_ascii_alphanumeric() && !"-._".contains(c) {
            return Err(report_err());
        }
    }
    Ok(())
}

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

    #[test]
    fn test_config_validate() {
        let mut cfg = Config::default();
        assert!(cfg.advertise_addr.is_empty());
        cfg.validate().unwrap();
        assert_eq!(cfg.addr, cfg.advertise_addr);

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.concurrent_send_snap_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.concurrent_recv_snap_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.end_point_recursion_limit = 0;
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.end_point_request_max_handle_duration = ReadableDuration::secs(0);
        assert!(invalid_cfg.validate().is_err());

        invalid_cfg = Config::default();
        invalid_cfg.addr = "0.0.0.0:1000".to_owned();
        assert!(invalid_cfg.validate().is_err());
        invalid_cfg.advertise_addr = "127.0.0.1:1000".to_owned();
        invalid_cfg.validate().unwrap();

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.advertise_addr = "127.0.0.1:1000".to_owned();
        invalid_cfg.status_addr = "127.0.0.1:1000".to_owned();
        assert!(invalid_cfg.validate().is_err());

        let mut invalid_cfg = cfg.clone();
        invalid_cfg.grpc_stream_initial_window_size = ReadableSize(i32::MAX as u64 + 1);
        assert!(invalid_cfg.validate().is_err());

        cfg.labels.insert("k1".to_owned(), "v1".to_owned());
        cfg.validate().unwrap();
        cfg.labels.insert("k2".to_owned(), "v2?".to_owned());
        assert!(cfg.validate().is_err());
    }

    #[test]
    fn test_store_labels() {
        let invalid_cases = vec!["", "123*", ".123", "💖"];

        for case in invalid_cases {
            assert!(validate_label(case, "dummy").is_err());
        }

        let valid_cases = vec![
            "a", "0", "a.1-2", "Cab", "abC", "b_1.2", "cab-012", "3ac.8b2",
        ];

        for case in valid_cases {
            validate_label(case, "dummy").unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use endpoint::Endpoint;
use options::Options;
use result::ZmqResult;
use socket_base::{FeedChannel, SocketBase, SocketMessage};
use v2_decoder::V2Decoder;

use std::io::extensions;
use std::io::{TcpStream, Reader};
use std::sync::{RWLock, Arc};

static V2_GREETING_SIZE: uint = 12;
static NO_PROGRESS_LIMIT: uint = 1000;
static SIGNATURE_SIZE: uint = 10;
static ZMTP_1_0: u8 = 0;
static ZMTP_2_0: u8 = 1;
static REVISION_POS: uint = 10;

fn proxy_write(chan: Receiver<Box<Vec<u8>>>, mut stream: TcpStream) {
    loop {
        match chan.recv_opt() {
            Ok(buf) => match stream.write(buf.as_slice()) {
                Err(_) => break,
                _ => ()
            },
            _ => break
        }
    }
}

struct InnerStreamEngine {
    chan_to_socket: Sender<ZmqResult<SocketMessage>>,
    stream: TcpStream,
    options: Arc<RWLock<Options>>,
    sender: Sender<Box<Vec<u8>>>,
    decoder: Option<V2Decoder>,

    // a sender to unblock all receivers on drop
    _death_notifier: Option<Sender<u8>>,
}

impl InnerStreamEngine {
    fn run(&mut self) {
        let mut signature = box vec!();
        signature.push(0xffu8);
        extensions::u64_to_be_bytes(
            (self.options.read().identity_size + 1) as u64, 8, |v| signature.push_all(v));
        signature.push(0x7fu8);
        self.sender.send(signature);

        self.handshake();

        assert!(self.decoder.is_some());
        let (tx, rx) = channel(); // TODO: replace with SyncSender
        self.chan_to_socket.send(Ok(FeedChannel(rx))) ;

        loop {
            match self.decoder.get_mut_ref().decode(&mut self.stream) {
                Ok(msg) => tx.send(msg),
                Err(e) => {
                    self.chan_to_socket.send(Err(e));
                    break;
                }
            }
        }
    }

    fn handshake(&mut self) {
        let mut greeting_recv = [0u8, ..V2_GREETING_SIZE];
        let mut greeting_bytes_read = 0;
        let mut zeros = 0;
        let mut type_sent = false;

        while greeting_bytes_read < V2_GREETING_SIZE {
            match self.stream.read(greeting_recv.mut_slice_from(greeting_bytes_read)) {
                Ok(0) => {
                    zeros += 1;
                    if zeros > NO_PROGRESS_LIMIT {
                        return; // TODO: error
                    } else {
                        continue;
                    }
                }
                Ok(n) => {
                    greeting_bytes_read += n;
                }
                _ => return, // TODO: error
            }

            //  We have received at least one byte from the peer.
            //  If the first byte is not 0xff, we know that the
            //  peer is using unversioned protocol.
            if greeting_recv[0] != 0xff {
                return; // TODO: error or ZMTP 1.0
            }

            if greeting_bytes_read < SIGNATURE_SIZE {
                continue;
            }

            //  Inspect the right-most bit of the 10th byte (which coincides
            //  with the 'flags' field if a regular message was sent).
            //  Zero indicates this is a header of identity message
            //  (i.e. the peer is using the unversioned protocol).
            if greeting_recv[9] & 0x01 == 0 {
                return; // TODO: error or ZMTP 1.0
            }

            //  The peer is using versioned protocol.
            //  Send the version number.
            self.sender.send(box [1u8].into_owned());

            if greeting_bytes_read > SIGNATURE_SIZE && !type_sent {
                type_sent = true;
                match greeting_recv[10] {
                    ZMTP_1_0 | ZMTP_2_0 => {
                        self.sender.send(box [self.options.read().type_ as u8].into_owned());
                    }
                    _ => {
                        //TODO: error or ZMTP 3.0
                        self.sender.send(box [self.options.read().type_ as u8].into_owned());
                    }
                }
            }
        }

        if greeting_recv[0] != 0xff || greeting_recv[9] & 0x01 == 0 {
            // TODO: error or ZMTP 1.0
        } else if greeting_recv[REVISION_POS] == ZMTP_1_0 {
            // TODO: error or ZMTP 1.0
        } else {
            assert!(self.decoder.is_none());
            self.decoder = Some(V2Decoder::new(self.options.read().maxmsgsize));
            //TODO: set encoder
        }
    }
}

pub struct StreamEngine {
    // the normal channel for SocketMessage
    chan_from_inner: Receiver<ZmqResult<SocketMessage>>,

    // a send handle
    sender: Sender<Box<Vec<u8>>>,
}

impl StreamEngine {
    pub fn new(stream: TcpStream, options: Arc<RWLock<Options>>,
               death_notifier: Option<Sender<u8>>) -> StreamEngine {
        // the normal channel for SocketMessage
        let (chan_to_socket, chan_from_inner) = channel();

        // two handles of one TcpStream: send and recv
        let receiver = stream.clone();

        // the channel for sending data
        let (stx, srx) = channel();
        let stx2 = stx.clone();

        spawn(proc() {
            let mut engine = InnerStreamEngine {
                chan_to_socket: chan_to_socket,
                stream: receiver,
                options: options,
                sender: stx2,
                decoder: None,
                _death_notifier: death_notifier,
            };
            engine.run();
            let _ = engine.stream.close_read();
            let _ = engine.stream.close_write();
        });
        spawn(proc() {
            proxy_write(srx, stream);
        });

        StreamEngine {
            chan_from_inner: chan_from_inner,
            sender: stx,
        }
    }
}

impl Endpoint for StreamEngine {
    fn get_chan<'a>(&'a self) -> &'a Receiver<ZmqResult<SocketMessage>> {
        &self.chan_from_inner
    }

    fn in_event(&mut self, msg: ZmqResult<SocketMessage>, socket: &mut SocketBase) {
        match msg {
            Ok(FeedChannel(rx)) => socket.send_back(Ok(FeedChannel(rx))),
            _ => ()
        }
    }
}
<commit_msg>Remove useless channel end.<commit_after>use endpoint::Endpoint;
use options::Options;
use result::ZmqResult;
use socket_base::{FeedChannel, SocketBase, SocketMessage};
use v2_decoder::V2Decoder;

use std::io::extensions;
use std::io::{TcpStream, Reader};
use std::sync::{RWLock, Arc};

static V2_GREETING_SIZE: uint = 12;
static NO_PROGRESS_LIMIT: uint = 1000;
static SIGNATURE_SIZE: uint = 10;
static ZMTP_1_0: u8 = 0;
static ZMTP_2_0: u8 = 1;
static REVISION_POS: uint = 10;

fn proxy_write(chan: Receiver<Box<Vec<u8>>>, mut stream: TcpStream) {
    loop {
        match chan.recv_opt() {
            Ok(buf) => match stream.write(buf.as_slice()) {
                Err(_) => break,
                _ => ()
            },
            _ => break
        }
    }
}

struct InnerStreamEngine {
    chan_to_socket: Sender<ZmqResult<SocketMessage>>,
    stream: TcpStream,
    options: Arc<RWLock<Options>>,
    sender: Sender<Box<Vec<u8>>>,
    decoder: Option<V2Decoder>,

    // a sender to unblock all receivers on drop
    _death_notifier: Option<Sender<u8>>,
}

impl InnerStreamEngine {
    fn run(&mut self) {
        let mut signature = box vec!();
        signature.push(0xffu8);
        extensions::u64_to_be_bytes(
            (self.options.read().identity_size + 1) as u64, 8, |v| signature.push_all(v));
        signature.push(0x7fu8);
        self.sender.send(signature);

        self.handshake();

        assert!(self.decoder.is_some());
        let (tx, rx) = channel(); // TODO: replace with SyncSender
        self.chan_to_socket.send(Ok(FeedChannel(rx))) ;

        loop {
            match self.decoder.get_mut_ref().decode(&mut self.stream) {
                Ok(msg) => tx.send(msg),
                Err(e) => {
                    self.chan_to_socket.send(Err(e));
                    break;
                }
            }
        }
    }

    fn handshake(&mut self) {
        let mut greeting_recv = [0u8, ..V2_GREETING_SIZE];
        let mut greeting_bytes_read = 0;
        let mut zeros = 0;
        let mut type_sent = false;

        while greeting_bytes_read < V2_GREETING_SIZE {
            match self.stream.read(greeting_recv.mut_slice_from(greeting_bytes_read)) {
                Ok(0) => {
                    zeros += 1;
                    if zeros > NO_PROGRESS_LIMIT {
                        return; // TODO: error
                    } else {
                        continue;
                    }
                }
                Ok(n) => {
                    greeting_bytes_read += n;
                }
                _ => return, // TODO: error
            }

            //  We have received at least one byte from the peer.
            //  If the first byte is not 0xff, we know that the
            //  peer is using unversioned protocol.
            if greeting_recv[0] != 0xff {
                return; // TODO: error or ZMTP 1.0
            }

            if greeting_bytes_read < SIGNATURE_SIZE {
                continue;
            }

            //  Inspect the right-most bit of the 10th byte (which coincides
            //  with the 'flags' field if a regular message was sent).
            //  Zero indicates this is a header of identity message
            //  (i.e. the peer is using the unversioned protocol).
            if greeting_recv[9] & 0x01 == 0 {
                return; // TODO: error or ZMTP 1.0
            }

            //  The peer is using versioned protocol.
            //  Send the version number.
            self.sender.send(box [1u8].into_owned());

            if greeting_bytes_read > SIGNATURE_SIZE && !type_sent {
                type_sent = true;
                match greeting_recv[10] {
                    ZMTP_1_0 | ZMTP_2_0 => {
                        self.sender.send(box [self.options.read().type_ as u8].into_owned());
                    }
                    _ => {
                        //TODO: error or ZMTP 3.0
                        self.sender.send(box [self.options.read().type_ as u8].into_owned());
                    }
                }
            }
        }

        if greeting_recv[0] != 0xff || greeting_recv[9] & 0x01 == 0 {
            // TODO: error or ZMTP 1.0
        } else if greeting_recv[REVISION_POS] == ZMTP_1_0 {
            // TODO: error or ZMTP 1.0
        } else {
            assert!(self.decoder.is_none());
            self.decoder = Some(V2Decoder::new(self.options.read().maxmsgsize));
            //TODO: set encoder
        }
    }
}

pub struct StreamEngine {
    // the normal channel for SocketMessage
    chan_from_inner: Receiver<ZmqResult<SocketMessage>>,
}

impl StreamEngine {
    pub fn new(stream: TcpStream, options: Arc<RWLock<Options>>,
               death_notifier: Option<Sender<u8>>) -> StreamEngine {
        // the normal channel for SocketMessage
        let (chan_to_socket, chan_from_inner) = channel();

        // two handles of one TcpStream: send and recv
        let receiver = stream.clone();

        // the channel for sending data
        let (stx, srx) = channel();

        spawn(proc() {
            let mut engine = InnerStreamEngine {
                chan_to_socket: chan_to_socket,
                stream: receiver,
                options: options,
                sender: stx,
                decoder: None,
                _death_notifier: death_notifier,
            };
            engine.run();
            let _ = engine.stream.close_read();
            let _ = engine.stream.close_write();
        });
        spawn(proc() {
            proxy_write(srx, stream);
        });

        StreamEngine {
            chan_from_inner: chan_from_inner,
        }
    }
}

impl Endpoint for StreamEngine {
    fn get_chan<'a>(&'a self) -> &'a Receiver<ZmqResult<SocketMessage>> {
        &self.chan_from_inner
    }

    fn in_event(&mut self, msg: ZmqResult<SocketMessage>, socket: &mut SocketBase) {
        match msg {
            Ok(FeedChannel(rx)) => socket.send_back(Ok(FeedChannel(rx))),
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>extern crate stratis_shared as shared;

use std::mem::transmute;
use std::io::Write;
use std::net::Shutdown;

use shared::client::Client;
use shared::Uuid;

#[no_mangle]
pub extern fn new_client() -> *mut Client {
    unsafe { transmute(Box::new(Client::new())) }
}

#[no_mangle]
pub extern fn default_client(key: [u8;20], uuid: [u8;16]) -> *mut Client {
    if let Ok(id) = Uuid::from_bytes(&uuid) {
        unsafe { transmute(Box::new(Client::default(key, id))) }
    }
    else { new_client() }
}

#[no_mangle]
pub extern fn drop_client(cptr: *mut Client) {
    let bc: Box<Client> = unsafe { transmute(cptr) };
    let c: Client = *bc;
    if let Some(ms) = c.stream {
        if let Ok(mut s) = ms.lock() {
            let _ = s.flush();
            let _ = s.shutdown(Shutdown::Both);
        }
    }
}

//TODO: figure out refs, or just use a cstruct perhaps?
#[no_mangle]
pub extern fn get_client_id(cptr: *mut Client) -> [u8;16] {
    let client = unsafe { & *cptr };
    let mut id = [0u8;16];
    for (i,n) in client.base.id.as_bytes().iter().enumerate() {
        id[i] = *n;
    }

    id
}

#[no_mangle]
pub extern fn get_client_key(cptr: *mut Client) -> [u8;20] {
    let client = unsafe { & *cptr };
    let mut key = [0u8;20];
    for (i,n) in client.base.key.iter().enumerate() {
        key[i] = *n;
    }

    key
}

//TODO: server-ip as arg
#[no_mangle]
pub extern fn client_connect(cptr: *mut Client) -> bool {
    let mut client = unsafe { &mut *cptr };
    client.connect("127.0.0.1:9996");
    client.stream.is_some()
}
#[no_mangle]
pub extern fn client_login(cptr: *mut Client) -> bool {
    let mut client = unsafe { &mut *cptr };
    client.login()
}
#[no_mangle]
pub extern fn client_register(cptr: *mut Client) {
    let mut client = unsafe { &mut *cptr };
    client.register();
}

/// these are highly OS dependent
#[no_mangle]
pub extern fn client_save(cptr: *mut Client) -> bool {
    let client = unsafe { & *cptr };
    Client::save(&client, "game/client.key")
}
#[no_mangle]
pub extern fn client_load(cptr: *mut Client) -> bool {
    let mut client = unsafe { &mut *cptr };
    if let Some(c) = Client::load_file("game/client.key") {
        client.base = c.base;
        true
    }
    else { false }
}
<commit_msg>chat and nick ffi<commit_after>extern crate stratis_shared as shared;

use std::mem::transmute;
use std::io::Write;
use std::net::Shutdown;

use std::os::raw::c_char;
use std::ffi::CStr;
use std::str;
use std::str::Utf8Error;

use shared::client::Client;
use shared::Uuid;

fn str_from_ptr<'a> (s: *const c_char) -> Result<&'a str,Utf8Error> {
    let cstr = unsafe { CStr::from_ptr(s) };
    str::from_utf8(cstr.to_bytes())
}

#[no_mangle]
pub extern fn new_client() -> *mut Client {
    unsafe { transmute(Box::new(Client::new())) }
}

#[no_mangle]
pub extern fn default_client(key: [u8;20], uuid: [u8;16]) -> *mut Client {
    if let Ok(id) = Uuid::from_bytes(&uuid) {
        unsafe { transmute(Box::new(Client::default(key, id))) }
    }
    else { new_client() }
}

#[no_mangle]
pub extern fn drop_client(cptr: *mut Client) {
    let bc: Box<Client> = unsafe { transmute(cptr) };
    let c: Client = *bc;
    if let Some(ms) = c.stream {
        if let Ok(mut s) = ms.lock() {
            let _ = s.flush();
            let _ = s.shutdown(Shutdown::Both);
        }
    }
}

//TODO: figure out refs, or just use a cstruct perhaps?
#[no_mangle]
pub extern fn get_client_id(cptr: *mut Client) -> [u8;16] {
    let client = unsafe { & *cptr };
    let mut id = [0u8;16];
    for (i,n) in client.base.id.as_bytes().iter().enumerate() {
        id[i] = *n;
    }

    id
}

#[no_mangle]
pub extern fn get_client_key(cptr: *mut Client) -> [u8;20] {
    let client = unsafe { & *cptr };
    let mut key = [0u8;20];
    for (i,n) in client.base.key.iter().enumerate() {
        key[i] = *n;
    }

    key
}

#[no_mangle]
pub extern fn client_connect(cptr: *mut Client, s: *const c_char) -> bool {
    let mut client = unsafe { &mut *cptr };
    if let Ok(s) = str_from_ptr(s) {
        client.connect(s);
    }
    client.stream.is_some()
}
#[no_mangle]
pub extern fn client_login(cptr: *mut Client) -> bool {
    let mut client = unsafe { &mut *cptr };
    client.login()
}
#[no_mangle]
pub extern fn client_register(cptr: *mut Client) {
    let mut client = unsafe { &mut *cptr };
    client.register();
}

/// these are highly OS dependent
#[no_mangle]
pub extern fn client_save(cptr: *mut Client) -> bool {
    let client = unsafe { & *cptr };
    Client::save(&client, "client.key")
}
#[no_mangle]
pub extern fn client_load(cptr: *mut Client) -> bool {
    let mut client = unsafe { &mut *cptr };
    if let Some(c) = Client::load_file("client.key") {
        client.base = c.base;
        true
    }
    else { false }
}

#[no_mangle]
pub extern fn client_chat(cptr: *mut Client, s: *const c_char) {
    let mut client = unsafe { &mut *cptr };
    if let Ok(s) = str_from_ptr(s) {
        client.chat(s);
    }
}
#[no_mangle]
pub extern fn client_nick(cptr: *mut Client, s: *const c_char) {
    let mut client = unsafe { &mut *cptr };
    if let Ok(s) = str_from_ptr(s) {
        client.nick(s);
    }
}
<|endoftext|>


<commit_before>//! Check logic for instructions

use util::bigint::M256;
use util::gas::Gas;

use vm::{Memory, Instruction};
use vm::errors::{MachineError, EvalError};

use vm::eval::{State, ControlCheck};
use super::util::check_range;

#[allow(unused_variables)]
pub fn extra_check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>, stipend_gas: Gas, after_gas: Gas) -> Result<(), EvalError> {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE | Instruction::DELEGATECALL => {
            if after_gas < state.stack.peek(0).unwrap().into() {
                Err(EvalError::Machine(MachineError::EmptyGas))
            } else {
                Ok(())
            }
        },
        _ => Ok(())
    }
}

#[allow(unused_variables)]
/// Check whether `run_opcode` would fail without mutating any of the
/// machine state.
pub fn check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Result<Option<ControlCheck>, EvalError> {
    match instruction {
        Instruction::STOP => Ok(None),
        Instruction::ADD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MUL => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SUB => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::DIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SDIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SMOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ADDMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::MULMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::EXP => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SIGNEXTEND => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::LT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::GT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SLT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SGT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::EQ => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ISZERO => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::AND => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::OR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::XOR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::NOT => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::BYTE => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::SHA3 => {
            state.stack.check_pop_push(2, 1)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },

        Instruction::ADDRESS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::BALANCE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::ORIGIN => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLVALUE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATALOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::CALLDATASIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATACOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::CODESIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CODECOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::GASPRICE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::EXTCODESIZE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::EXTCODECOPY => {
            state.stack.check_pop_push(4, 0)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            state.memory.check_write_range(
                state.stack.peek(1).unwrap(), state.stack.peek(3).unwrap())?;
            Ok(None)
        },

        Instruction::BLOCKHASH => {
            state.stack.check_pop_push(1, 1)?;
            let current_number = state.block.number;
            let number = state.stack.peek(0).unwrap();
            if !(number >= current_number || current_number - number > M256::from(256u64)) {
                state.blockhash_state.get(number)?;
            }
            Ok(None)
        },
        Instruction::COINBASE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::TIMESTAMP => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::NUMBER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::DIFFICULTY => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GASLIMIT => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::POP => { state.stack.check_pop_push(1, 0)?; Ok(None) },
        Instruction::MLOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::MSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::MSTORE8 => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SLOAD => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::JUMP => {
            state.stack.check_pop_push(1, 0)?;
            Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
        },
        Instruction::JUMPI => {
            state.stack.check_pop_push(2, 0)?;
            if state.stack.peek(1).unwrap() != M256::zero() {
                Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
            } else {
                Ok(None)
            }
        },
        Instruction::PC => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::MSIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GAS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::JUMPDEST => Ok(None),

        Instruction::PUSH(v) => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::DUP(v) => { state.stack.check_pop_push(v, v+1)?; Ok(None) },
        Instruction::SWAP(v) => { state.stack.check_pop_push(v+1, v+1)?; Ok(None) },

        Instruction::LOG(v) => {
            state.stack.check_pop_push(v+2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::CREATE => {
            state.stack.check_pop_push(3, 1)?;
            check_range(state.stack.peek(1).unwrap(), state.stack.peek(2).unwrap())?;
            state.account_state.require(state.context.address)?;
            Ok(None)
        },
        Instruction::CALL => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::CALLCODE => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::RETURN => {
            state.stack.check_pop_push(2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::DELEGATECALL => {
            state.stack.check_pop_push(6, 1)?;
            check_range(state.stack.peek(2).unwrap(), state.stack.peek(3).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(4).unwrap(), state.stack.peek(5).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::SUICIDE => {
            state.stack.check_pop_push(1, 0)?;
            state.account_state.require(state.context.address)?;
            let balance = state.account_state.balance(state.context.address).unwrap();
            if state.patch.ignore_suicide_zero_balance && balance == U256::zero() {
                // Do not require target account in this case.
            } else {
                state.account_state.require(state.stack.peek(0).unwrap().into())?;
            }
            Ok(None)
        },
    }
}
<commit_msg>Revert "check: support ignore zero balance for suicide"<commit_after>//! Check logic for instructions

use util::bigint::M256;
use util::gas::Gas;

use vm::{Memory, Instruction};
use vm::errors::{MachineError, EvalError};

use vm::eval::{State, ControlCheck};
use super::util::check_range;

#[allow(unused_variables)]
pub fn extra_check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>, stipend_gas: Gas, after_gas: Gas) -> Result<(), EvalError> {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE | Instruction::DELEGATECALL => {
            if after_gas < state.stack.peek(0).unwrap().into() {
                Err(EvalError::Machine(MachineError::EmptyGas))
            } else {
                Ok(())
            }
        },
        _ => Ok(())
    }
}

#[allow(unused_variables)]
/// Check whether `run_opcode` would fail without mutating any of the
/// machine state.
pub fn check_opcode<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Result<Option<ControlCheck>, EvalError> {
    match instruction {
        Instruction::STOP => Ok(None),
        Instruction::ADD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MUL => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SUB => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::DIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SDIV => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::MOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SMOD => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ADDMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::MULMOD => { state.stack.check_pop_push(3, 1)?; Ok(None) },
        Instruction::EXP => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SIGNEXTEND => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::LT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::GT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SLT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::SGT => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::EQ => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::ISZERO => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::AND => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::OR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::XOR => { state.stack.check_pop_push(2, 1)?; Ok(None) },
        Instruction::NOT => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::BYTE => { state.stack.check_pop_push(2, 1)?; Ok(None) },

        Instruction::SHA3 => {
            state.stack.check_pop_push(2, 1)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },

        Instruction::ADDRESS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::BALANCE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::ORIGIN => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLVALUE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATALOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::CALLDATASIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CALLDATACOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::CODESIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::CODECOPY => {
            state.stack.check_pop_push(3, 0)?;
            state.memory.check_write_range(
                state.stack.peek(0).unwrap(), state.stack.peek(2).unwrap())?;
            Ok(None)
        },
        Instruction::GASPRICE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::EXTCODESIZE => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
        Instruction::EXTCODECOPY => {
            state.stack.check_pop_push(4, 0)?;
            state.account_state.require_code(state.stack.peek(0).unwrap().into())?;
            state.memory.check_write_range(
                state.stack.peek(1).unwrap(), state.stack.peek(3).unwrap())?;
            Ok(None)
        },

        Instruction::BLOCKHASH => {
            state.stack.check_pop_push(1, 1)?;
            let current_number = state.block.number;
            let number = state.stack.peek(0).unwrap();
            if !(number >= current_number || current_number - number > M256::from(256u64)) {
                state.blockhash_state.get(number)?;
            }
            Ok(None)
        },
        Instruction::COINBASE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::TIMESTAMP => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::NUMBER => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::DIFFICULTY => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GASLIMIT => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::POP => { state.stack.check_pop_push(1, 0)?; Ok(None) },
        Instruction::MLOAD => { state.stack.check_pop_push(1, 1)?; Ok(None) },
        Instruction::MSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::MSTORE8 => {
            state.stack.check_pop_push(2, 0)?;
            state.memory.check_write(state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SLOAD => {
            state.stack.check_pop_push(1, 1)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::SSTORE => {
            state.stack.check_pop_push(2, 0)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require_storage(state.context.address, state.stack.peek(0).unwrap())?;
            Ok(None)
        },
        Instruction::JUMP => {
            state.stack.check_pop_push(1, 0)?;
            Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
        },
        Instruction::JUMPI => {
            state.stack.check_pop_push(2, 0)?;
            if state.stack.peek(1).unwrap() != M256::zero() {
                Ok(Some(ControlCheck::Jump(state.stack.peek(0).unwrap())))
            } else {
                Ok(None)
            }
        },
        Instruction::PC => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::MSIZE => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::GAS => { state.stack.check_pop_push(0, 1)?; Ok(None) },
        Instruction::JUMPDEST => Ok(None),

        Instruction::PUSH(v) => { state.stack.check_pop_push(0, 1)?; Ok(None) },

        Instruction::DUP(v) => { state.stack.check_pop_push(v, v+1)?; Ok(None) },
        Instruction::SWAP(v) => { state.stack.check_pop_push(v+1, v+1)?; Ok(None) },

        Instruction::LOG(v) => {
            state.stack.check_pop_push(v+2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::CREATE => {
            state.stack.check_pop_push(3, 1)?;
            check_range(state.stack.peek(1).unwrap(), state.stack.peek(2).unwrap())?;
            state.account_state.require(state.context.address)?;
            Ok(None)
        },
        Instruction::CALL => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::CALLCODE => {
            state.stack.check_pop_push(7, 1)?;
            check_range(state.stack.peek(3).unwrap(), state.stack.peek(4).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(5).unwrap(), state.stack.peek(6).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::RETURN => {
            state.stack.check_pop_push(2, 0)?;
            check_range(state.stack.peek(0).unwrap(), state.stack.peek(1).unwrap())?;
            Ok(None)
        },
        Instruction::DELEGATECALL => {
            state.stack.check_pop_push(6, 1)?;
            check_range(state.stack.peek(2).unwrap(), state.stack.peek(3).unwrap())?;
            state.memory.check_write_range(
                state.stack.peek(4).unwrap(), state.stack.peek(5).unwrap())?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(1).unwrap().into())?;
            Ok(None)
        },
        Instruction::SUICIDE => {
            state.stack.check_pop_push(1, 0)?;
            state.account_state.require(state.context.address)?;
            state.account_state.require(state.stack.peek(0).unwrap().into())?;
            Ok(None)
        },
    }
}
<|endoftext|>


<commit_before>
use std::{ptr};
use std::mem::{transmute};
pub struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(windows)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        unsafe {
            let mut name = path.as_str().unwrap().to_utf16();
            name.push(0);
            let handle =
                CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(unix)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::posix88::fcntl::open;
        use libc::funcs::posix88::stat_::fstat;
        use libc::funcs::posix88::mman::mmap;
        use libc::consts::os::posix88::{O_RDONLY, PROT_READ, MAP_SHARED};
        use libc::types::os::arch::posix01::stat;
        unsafe {
            let name = name.to_c_str();
            let handle = open(name.as_bytes().as_ptr(), O_RDONLY);
            if (handle == -1) { return None; }
            let finfo: stat;
            if (fstat(handle, &finfo) == -1) { return None; }
            let size = finfo.st_size;
            let data =
                mmap(ptr::null(), size, PROT_READ, MAP_SHARED, handle, 0);
            if (data == -1) { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    fn get_header(&self) -> &Header { unsafe { transmute(self.header) } }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf); str::from_utf8(bytes) };
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> {
        self.file.get_str(self.data.name)
    }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<commit_msg>Fix POSIX implementation<commit_after>
use std::{ptr};
use std::mem::{transmute};
pub struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(windows)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        unsafe {
            let mut name = path.as_str().unwrap().to_utf16();
            name.push(0);
            let handle =
                CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(unix)]
    pub fn open(path: &Path) -> Option<File> {
        use libc::funcs::posix88::fcntl::open;
        use libc::funcs::posix88::stat_::fstat;
        use libc::funcs::posix88::mman::mmap;
        use libc::consts::os::posix88::{O_RDONLY, PROT_READ, MAP_SHARED};
        use libc::types::os::arch::posix01::stat;
        unsafe {
            let name = path.to_c_str();
            let handle = open(name.unwrap(), O_RDONLY, 0);
            if (handle == -1) { return None; }
            let mut finfo = std::mem::uninitialized::<stat>();
            if (fstat(handle, &mut finfo) == -1) { return None; }
            let size = finfo.st_size;
            let data =
                mmap(ptr::null(), size as u64, PROT_READ, MAP_SHARED, handle,
                     0);
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    fn get_header(&self) -> &Header { unsafe { transmute(self.header) } }
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        use std::str;
        use std::slice::raw;
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf); str::from_utf8(bytes) };
            raw::buf_as_slice(ptr.offset(2), (*size) as uint, func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
pub struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    pub fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    pub fn name(&self) -> Option<&'a str> {
        self.file.get_str(self.data.name)
    }
    pub fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
<|endoftext|>


<commit_before>use inkwell::context::Context;
use inkwell::AddressSpace;

#[test]
fn test_no_context_double_free() {
    let context = Context::create();
    let int = context.i8_type();

    {
        int.get_context();
    }
}

#[test]
fn test_no_context_double_free3() {
    unsafe {
        Context::get_global(|_ctx| ());
        Context::get_global(|_ctx| ());
    }
}

#[test]
fn test_get_context_from_contextless_value() {
    let context = Context::create();

    unsafe {
        Context::get_global(|global_context| {
            let int = global_context.i8_type();

            assert_ne!(int.get_context(), context);
            assert_eq!(int.get_context(), *global_context);
            assert_ne!(*global_context, context);
        })
    };
}

#[test]
fn test_basic_block_context() {
    let context = Context::create();
    let module = context.create_module("my_mod");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let fn_value = module.add_function("my_fn", fn_type, None);
    let basic_block = context.append_basic_block(fn_value, "entry");

    assert_eq!(basic_block.get_context(), context);
}

#[test]
fn test_values_get_context() {
    let context = Context::create();
    let void_type = context.void_type();
    let i8_type = context.i8_type();
    let f32_type = context.f32_type();
    let f32_vec_type = f32_type.vec_type(3);
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let f32_array_type = f32_type.array_type(2);
    let fn_type = f32_type.fn_type(&[], false);
    let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false);

    assert_eq!(f32_type.get_context(), context);
    assert_eq!(void_type.get_context(), context);
    assert_eq!(f32_vec_type.get_context(), context);
    assert_eq!(f32_ptr_type.get_context(), context);
    assert_eq!(f32_array_type.get_context(), context);
    assert_eq!(fn_type.get_context(), context);
    assert_eq!(i8_type.get_context(), context);
    assert_eq!(struct_type.get_context(), context);
}

#[test]
#[llvm_versions(12.0..=latest)]
fn test_get_type() {
    use inkwell::types::AnyTypeEnum;

    let context = Context::create();

    let name = "opaque";
    let opaque = context.opaque_struct_type(name);

    let got = context.get_type(name);
    assert_eq!(got, Some(AnyTypeEnum::from(opaque)));

    assert_eq!(context.get_type("non-existent"), None);
}
<commit_msg>Try reordering annotations to turn-off test<commit_after>use inkwell::context::Context;
use inkwell::AddressSpace;

#[test]
fn test_no_context_double_free() {
    let context = Context::create();
    let int = context.i8_type();

    {
        int.get_context();
    }
}

#[test]
fn test_no_context_double_free3() {
    unsafe {
        Context::get_global(|_ctx| ());
        Context::get_global(|_ctx| ());
    }
}

#[test]
fn test_get_context_from_contextless_value() {
    let context = Context::create();

    unsafe {
        Context::get_global(|global_context| {
            let int = global_context.i8_type();

            assert_ne!(int.get_context(), context);
            assert_eq!(int.get_context(), *global_context);
            assert_ne!(*global_context, context);
        })
    };
}

#[test]
fn test_basic_block_context() {
    let context = Context::create();
    let module = context.create_module("my_mod");
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let fn_value = module.add_function("my_fn", fn_type, None);
    let basic_block = context.append_basic_block(fn_value, "entry");

    assert_eq!(basic_block.get_context(), context);
}

#[test]
fn test_values_get_context() {
    let context = Context::create();
    let void_type = context.void_type();
    let i8_type = context.i8_type();
    let f32_type = context.f32_type();
    let f32_vec_type = f32_type.vec_type(3);
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let f32_array_type = f32_type.array_type(2);
    let fn_type = f32_type.fn_type(&[], false);
    let struct_type = context.struct_type(&[i8_type.into(), f32_type.into()], false);

    assert_eq!(f32_type.get_context(), context);
    assert_eq!(void_type.get_context(), context);
    assert_eq!(f32_vec_type.get_context(), context);
    assert_eq!(f32_ptr_type.get_context(), context);
    assert_eq!(f32_array_type.get_context(), context);
    assert_eq!(fn_type.get_context(), context);
    assert_eq!(i8_type.get_context(), context);
    assert_eq!(struct_type.get_context(), context);
}

#[llvm_versions(12.0..=latest)]
#[test]
fn test_get_type() {
    use inkwell::types::AnyTypeEnum;

    let context = Context::create();

    let name = "opaque";
    let opaque = context.opaque_struct_type(name);

    let got = context.get_type(name);
    assert_eq!(got, Some(AnyTypeEnum::from(opaque)));

    assert_eq!(context.get_type("non-existent"), None);
}
<|endoftext|>


<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::get_value;

pub fn bragi_stops_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    stop_attached_to_admin_test(&bragi);
    stop_no_admin_test(&bragi);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops_dataset2.txt".into(),
                             "--dataset=dataset2".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    stop_filtred_by_dataset_test(&bragi);
}

fn stop_attached_to_admin_test(bragi: &BragiHandler) {
    // with this query we should find only one response, a stop
    let response = bragi.get("/autocomplete?q=14 juillet");
    assert_eq!(response.len(), 1);
    let stop = response.first().unwrap();

    assert_eq!(get_value(stop, "type"), "public_transport:stop_area");
    assert_eq!(get_value(stop, "label"), "14 Juillet");
    assert_eq!(get_value(stop, "name"), "14 Juillet");
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");
    assert_eq!(get_value(stop, "citycode"), "77487");

    // this stop area is in the boundary of the admin 'Vaux-le-Pénil',
    // it should have been associated to it
    assert_eq!(get_value(stop, "city"), "Vaux-le-Pénil");
    let admins = stop.get("administrative_regions").and_then(|a| a.as_array());
    assert_eq!(admins.map(|a| a.len()).unwrap_or(0), 1);
}

fn stop_no_admin_test(bragi: &BragiHandler) {
    // we query another stop, but this one is outside the range of an admin,
    // we should get the stop, but with no admin attached to it
    let response = bragi.get("/autocomplete?q=Far west station");
    assert_eq!(response.len(), 1);
    let stop = response.first().unwrap();

    assert_eq!(get_value(stop, "type"), "public_transport:stop_area");
    assert_eq!(get_value(stop, "label"), "Far west station");
    assert_eq!(get_value(stop, "name"), "Far west station");
    assert_eq!(get_value(stop, "id"), "stop_area:SA:station_no_city");
    assert_eq!(get_value(stop, "city"), "");
    let admins = stop.get("administrative_regions").and_then(|a| a.as_array());
    assert_eq!(admins.map(|a| a.len()).unwrap_or(0), 0);
}

fn stop_filtred_by_dataset_test(bragi: &BragiHandler) {
    // All stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    assert_eq!(response.len(), 2);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");

    let stop = response.last().unwrap();
    assert_eq!(get_value(stop, "id"),
        "stop_area:SA:second_station:dataset2");

    // filter by dataset1
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1");

    assert_eq!(response.len(), 1);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");
    // filter by dataset2
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset2");

    assert_eq!(response.len(), 1);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"),
        "stop_area:SA:second_station:dataset2");
}
<commit_msg>correction<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::get_value;

pub fn bragi_stops_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    stop_attached_to_admin_test(&bragi);
    stop_no_admin_test(&bragi);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops_dataset2.txt".into(),
                             "--dataset=dataset2".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    stop_filtred_by_dataset_test(&bragi);
}

fn stop_attached_to_admin_test(bragi: &BragiHandler) {
    // with this query we should find only one response, a stop
    let response = bragi.get("/autocomplete?q=14 juillet");
    assert_eq!(response.len(), 1);
    let stop = response.first().unwrap();

    assert_eq!(get_value(stop, "type"), "public_transport:stop_area");
    assert_eq!(get_value(stop, "label"), "14 Juillet");
    assert_eq!(get_value(stop, "name"), "14 Juillet");
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");
    assert_eq!(get_value(stop, "citycode"), "77487");

    // this stop area is in the boundary of the admin 'Vaux-le-Pénil',
    // it should have been associated to it
    assert_eq!(get_value(stop, "city"), "Vaux-le-Pénil");
    let admins = stop.get("administrative_regions").and_then(|a| a.as_array());
    assert_eq!(admins.map(|a| a.len()).unwrap_or(0), 1);
}

fn stop_no_admin_test(bragi: &BragiHandler) {
    // we query another stop, but this one is outside the range of an admin,
    // we should get the stop, but with no admin attached to it
    let response = bragi.get("/autocomplete?q=Far west station");
    assert_eq!(response.len(), 1);
    let stop = response.first().unwrap();

    assert_eq!(get_value(stop, "type"), "public_transport:stop_area");
    assert_eq!(get_value(stop, "label"), "Far west station");
    assert_eq!(get_value(stop, "name"), "Far west station");
    assert_eq!(get_value(stop, "id"), "stop_area:SA:station_no_city");
    assert_eq!(get_value(stop, "city"), "");
    let admins = stop.get("administrative_regions").and_then(|a| a.as_array());
    assert_eq!(admins.map(|a| a.len()).unwrap_or(0), 0);
}

fn stop_filtered_by_dataset_test(bragi: &BragiHandler) {
    // All stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    assert_eq!(response.len(), 2);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");

    let stop = response.last().unwrap();
    assert_eq!(get_value(stop, "id"),
        "stop_area:SA:second_station:dataset2");

    // filter by dataset1
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1");

    assert_eq!(response.len(), 1);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"), "stop_area:SA:second_station");
    // filter by dataset2
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset2");

    assert_eq!(response.len(), 1);

    let stop = response.first().unwrap();
    assert_eq!(get_value(stop, "id"),
        "stop_area:SA:second_station:dataset2");
}
<|endoftext|>


<commit_before><commit_msg>Point: add tests for existing operators<commit_after><|endoftext|>


<commit_before>//! Timer

use core::any::{Any, TypeId};
use core::ops::Deref;

use cast::{u16, u32};
use hal;
use nb::{self, Error};
use stm32f411::{GPIOA, RCC, TIM3, TIM4, gpioa, tim3};

/// Channel associated to a timer
#[derive(Clone, Copy, Debug)]
pub enum Channel {
    /// TxC1
    _1,
    /// TxC2
    _2,
    /// TxC3
    _3,
    /// TxC4
    _4,
}

/// IMPLEMENTATION DETAIL
pub unsafe trait TIM: Deref<Target = tim3::RegisterBlock> {
    /// IMPLEMENTATION DETAIL
    type GPIO: Deref<Target = gpioa::RegisterBlock>;
}

unsafe impl TIM for TIM3 {
    type GPIO = GPIOA;
}

unsafe impl TIM for TIM4 {
    type GPIO = GPIOA;
}

/// `hal::Timer` implementation
pub struct Timer<'a, T>(pub &'a T) where T: 'a;

impl<'a, T> Clone for Timer<'a, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, T> Copy for Timer<'a, T> {}

impl<'a, T> Timer<'a, T>
    where T: Any + TIM
{
    /// Initializes the timer with a periodic timeout of `frequency` Hz
    ///
    /// NOTE After initialization, the timer will be in the paused state.
    pub fn init<P>(&self, period: P, rcc: &RCC)
        where P: Into<::apb1::Ticks>
    {
        self.init_(period.into(), rcc)
    }

    fn init_(&self, timeout: ::apb1::Ticks, rcc: &RCC) {
        let tim3 = self.0;

        // Enable TIMx
        if tim3.get_type_id() == TypeId::of::<TIM3>() {
            rcc.apb1enr.modify(|_, w| w.tim3en().set_bit());
        } else if tim3.get_type_id() == TypeId::of::<TIM4>() {
            rcc.apb1enr.modify(|_, w| w.tim4en().set_bit());
        }

        // Configure periodic update event
        self._set_timeout(timeout);

        // Continuous mode
        tim3.cr1.write(|w| w.opm().clear_bit());

        // Enable the update event interrupt
        tim3.dier.modify(|_, w| w.uie().set_bit());
    }

    fn _set_timeout(&self, timeout: ::apb1::Ticks) {
        let period = timeout.0;

        let psc = u16((period - 1) / (1 << 16)).unwrap();
        let arr = u16(period / u32(psc + 1)).unwrap();
        unsafe {
            self.0.psc.write(|w| w.psc().bits(psc));
            self.0.arr.write(|w| w.arr_l().bits(arr));
        }
    }
}

impl<'a, T> hal::Timer for Timer<'a, T>
    where T: Any + TIM
{
    type Time = ::apb1::Ticks;

    fn get_timeout(&self) -> ::apb1::Ticks {
        ::apb1::Ticks(u32(self.0.psc.read().psc().bits() + 1) * u32(self.0.arr.read().bits()))
    }

    fn pause(&self) {
        self.0.cr1.modify(|_, w| w.cen().clear_bit());
    }

    fn restart(&self) {
        unsafe {
            self.0.cnt.modify(|_, w| w.bits(0));
            self.0.cnt.write(|w| w.bits(0));
        }
    }

    fn resume(&self) {
        self.0.cr1.modify(|_, w| w.cen().set_bit());
    }

    fn set_timeout<TO>(&self, timeout: TO)
        where TO: Into<::apb1::Ticks>
    {
        self._set_timeout(timeout.into())
    }

    fn wait(&self) -> nb::Result<(), !> {
        if self.0.sr.read().uif().bit_is_clear() {
            Err(Error::WouldBlock)
        } else {
            self.0.sr.modify(|_, w| w.uif().clear_bit());
            Ok(())
        }
    }
}
<commit_msg>Updates to timer<commit_after>//! Timer

use core::any::{Any, TypeId};
use core::ops::Deref;
use core::marker::PhantomData;

use cast::{u16, u32};
use hal;
use nb::{self, Error};
use stm32f411::{GPIOA, TIM1, TIM3, TIM4, gpioa, tim3, tim1};

/// Channel associated to a timer
#[derive(Clone, Copy, Debug)]
pub enum Channel {
    /// TxC1
    _1,
    /// TxC2
    _2,
    /// TxC3
    _3,
    /// TxC4
    _4,
}

pub unsafe trait TIMBase {
    fn init(&self, timeout: ::apb1::Ticks);
    fn set_timeout(&self, timeout: ::apb1::Ticks);
}

unsafe impl TIMBase for tim3::RegisterBlock {
    fn init(&self, timeout: ::apb1::Ticks) {
        // Configure periodic update event
        self.set_timeout(timeout);

        // Continuous mode
        self.cr1.write(|w| w.opm().clear_bit());

        // Enable the update event interrupt
        self.dier.modify(|_, w| w.uie().set_bit());
    }

    fn set_timeout(&self, timeout: ::apb1::Ticks) {
        let period = timeout.0;

        let psc = u16((period - 1) / (1 << 16)).unwrap();
        let arr = u16(period / u32(psc + 1)).unwrap();
        unsafe {
            self.psc.write(|w| w.psc().bits(psc));
            self.arr.write(|w| w.arr_l().bits(arr));
        }
    }
}

unsafe impl TIMBase for tim1::RegisterBlock {
    fn init(&self, timeout: ::apb1::Ticks) {
        self.set_timeout(timeout);
        self.cr1.write(|w| w.opm().clear_bit());
        self.dier.modify(|_, w| w.uie().set_bit());
    }

    fn set_timeout(&self, timeout: ::apb1::Ticks) {
        let period = timeout.0;
        let psc = u16((period - 1) / (1 << 16)).unwrap();
        let arr = u16(period / u32(psc + 1)).unwrap();
        unsafe {
            self.psc.write(|w| w.psc().bits(psc));
            self.arr.write(|w| w.arr().bits(arr));
        }
    }
}

pub unsafe trait TIM<T>: Deref<Target = T>
    where T: TIMBase
{
    /// IMPLEMENTATION DETAIL
    type GPIO: Deref<Target = gpioa::RegisterBlock>;

    fn init_(&self, timeout: ::apb1::Ticks) {
        self.init(timeout);
    }

    fn set_timeout_(&self, timeout: ::apb1::Ticks) {
        self.set_timeout(timeout);
    }
}

unsafe impl TIM<tim3::RegisterBlock> for TIM3 {
    type GPIO = GPIOA;
}

unsafe impl TIM<tim3::RegisterBlock> for TIM4 {
    type GPIO = GPIOA;
}

unsafe impl TIM<tim1::RegisterBlock> for TIM1 {
    type GPIO = GPIOA;
}

pub struct Timer<'a, T, R>(pub &'a T, pub PhantomData<R>) where T: 'a;

// impl<'a, T, R> Clone for Timer<'a, T, R>
//     where R: TIMBase, T: Any + TIM<R>
// {
//     fn clone(&self) -> Self {
//         *self
//     }
// }

// impl<'a, T, R> Copy for Timer<'a, T, R> {}

impl<'a, T, R> Timer<'a, T, R>
    where R: TIMBase, T: Any + TIM<R>
{
    pub const fn new(tim: &'a T) -> Self {
        Timer(tim, PhantomData)
    }
    /// Initializes the timer with a periodic timeout of `frequency` Hz
    ///
    /// NOTE After initialization, the timer will be in the paused state.
    pub fn init<P>(&self, period: P)
        where P: Into<::apb1::Ticks>
    {
        self.0.init_(period.into());
    }
}

impl<'a, T> hal::Timer for Timer<'a, T, tim3::RegisterBlock>
    where T: Any + TIM<tim3::RegisterBlock>
{
    type Time = ::apb1::Ticks;

    fn get_timeout(&self) -> ::apb1::Ticks {
        ::apb1::Ticks(u32(self.0.psc.read().psc().bits() + 1) * u32(self.0.arr.read().bits()))
    }

    fn pause(&self) {
        self.0.cr1.modify(|_, w| w.cen().clear_bit());
    }

    fn restart(&self) {
        unsafe {
            self.0.cnt.modify(|_, w| w.bits(0));
            self.0.cnt.write(|w| w.bits(0));
        }
    }

    fn resume(&self) {
        self.0.cr1.modify(|_, w| w.cen().set_bit());
    }

    fn set_timeout<TO>(&self, timeout: TO)
        where TO: Into<::apb1::Ticks>
    {
        self.0.set_timeout_(timeout.into())
    }

    fn wait(&self) -> nb::Result<(), !> {
        if self.0.sr.read().uif().bit_is_clear() {
            Err(Error::WouldBlock)
        } else {
            self.0.sr.modify(|_, w| w.uif().clear_bit());
            Ok(())
        }
    }
}

impl<'a, T> hal::Timer for Timer<'a, T, tim1::RegisterBlock>
    where T: Any + TIM<tim1::RegisterBlock>
{
    type Time = ::apb1::Ticks;

    fn get_timeout(&self) -> ::apb1::Ticks {
        ::apb1::Ticks(u32(self.0.psc.read().psc().bits() + 1) * u32(self.0.arr.read().bits()))
    }

    fn pause(&self) {
        self.0.cr1.modify(|_, w| w.cen().clear_bit());
    }

    fn restart(&self) {
        unsafe {
            self.0.cnt.modify(|_, w| w.bits(0));
            self.0.cnt.write(|w| w.bits(0));
        }
    }

    fn resume(&self) {
        self.0.cr1.modify(|_, w| w.cen().set_bit());
    }

    fn set_timeout<TO>(&self, timeout: TO)
        where TO: Into<::apb1::Ticks>
    {
        self.0.set_timeout_(timeout.into())
    }

    fn wait(&self) -> nb::Result<(), !> {
        if self.0.sr.read().uif().bit_is_clear() {
            Err(Error::WouldBlock)
        } else {
            self.0.sr.modify(|_, w| w.uif().clear_bit());
            Ok(())
        }
    }
}<|endoftext|>