<commit_before>use nom::multispace;
use std::str;
use std::fmt;

use common::{field_list, opt_multispace, statement_terminator, table_reference, value_list,
             Literal};
use column::Column;
use table::Table;

#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize, Deserialize)]
pub struct InsertStatement {
    pub table: Table,
    pub fields: Vec<Column>,
    pub data: Vec<Vec<Literal>>,
    pub ignore: bool,
}

impl fmt::Display for InsertStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "INSERT INTO {}", self.table)?;
        write!(
            f,
            " ({})",
            self.fields
                .iter()
                .map(|ref col| col.name.to_owned())
                .collect::<Vec<_>>()
                .join(", ")
        )?;
        write!(
            f,
            " VALUES {}",
            self.data
                .iter()
                .map(|fields| format!(
                    "({})",
                    fields
                        .into_iter()
                        .map(|l| l.to_string())
                        .collect::<Vec<_>>()
                        .join(", ")
                ))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, multiple parens expr, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    complete!(do_parse!(
        tag_no_case!("insert") >>
        ignore: opt!(preceded!(multispace, tag_no_case!("ignore"))) >>
        multispace >>
        tag_no_case!("into") >>
        multispace >>
        table: table_reference >>
        opt_multispace >>
        fields: opt!(do_parse!(
                tag!("(") >>
                opt_multispace >>
                fields: field_list >>
                opt_multispace >>
                tag!(")") >>
                multispace >>
                (fields)
                )
            ) >>
        tag_no_case!("values") >>
        opt_multispace >>
        data: many1!(
            do_parse!(
                tag!("(") >>
                values: value_list >>
                tag!(")") >>
                opt!(
                    complete!(do_parse!(
                            opt_multispace >>
                            tag!(",") >>
                            opt_multispace >>
                            ()
                    ))
                ) >>
                (values)
            )
        ) >>
        statement_terminator >>
        ({
            // "table AS alias" isn't legal in INSERT statements
            assert!(table.alias.is_none());
            InsertStatement {
                table: table,
                fields: match fields {
                    Some(ref f) =>
                        f.iter()
                         .cloned()
                         .collect(),
                    None =>
                        data[0].iter()
                              .enumerate()
                              .map(|(i, _)| {
                                  Column::from(format!("{}", i).as_str())
                              })
                              .collect(),
                },
                data: data,
                ignore: ignore.is_some(),
            }
        })
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use table::Table;

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("0"), Column::from("1")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    #[test]
    fn complex_insert() {
        let qstring = "INSERT INTO users VALUES (42, 'test', \"test\", CURRENT_TIMESTAMP);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    Column::from("0"),
                    Column::from("1"),
                    Column::from("2"),
                    Column::from("3"),
                ],
                data: vec![
                    vec![
                        42.into(),
                        "test".into(),
                        "test".into(),
                        Literal::CurrentTimestamp,
                    ],
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn insert_with_field_names() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    // Issue #3
    #[test]
    fn insert_without_spaces() {
        let qstring = "INSERT INTO users(id, name) VALUES(42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    #[test]
    fn multi_insert() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\"),(21, \"test2\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![
                    vec![42.into(), "test".into()],
                    vec![21.into(), "test2".into()],
                ],
                ..Default::default()
            }
        );
    }
}
<commit_msg>Sometimes we actually fix TODOs<commit_after>use nom::multispace;
use std::str;
use std::fmt;

use common::{field_list, opt_multispace, statement_terminator, table_reference, value_list,
             Literal};
use column::Column;
use table::Table;

#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize, Deserialize)]
pub struct InsertStatement {
    pub table: Table,
    pub fields: Vec<Column>,
    pub data: Vec<Vec<Literal>>,
    pub ignore: bool,
}

impl fmt::Display for InsertStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "INSERT INTO {}", self.table)?;
        write!(
            f,
            " ({})",
            self.fields
                .iter()
                .map(|ref col| col.name.to_owned())
                .collect::<Vec<_>>()
                .join(", ")
        )?;
        write!(
            f,
            " VALUES {}",
            self.data
                .iter()
                .map(|fields| format!(
                    "({})",
                    fields
                        .into_iter()
                        .map(|l| l.to_string())
                        .collect::<Vec<_>>()
                        .join(", ")
                ))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }
}

/// Parse rule for a SQL insert query.
/// TODO(malte): support REPLACE, nested selection, DEFAULT VALUES
named!(pub insertion<&[u8], InsertStatement>,
    complete!(do_parse!(
        tag_no_case!("insert") >>
        ignore: opt!(preceded!(multispace, tag_no_case!("ignore"))) >>
        multispace >>
        tag_no_case!("into") >>
        multispace >>
        table: table_reference >>
        opt_multispace >>
        fields: opt!(do_parse!(
                tag!("(") >>
                opt_multispace >>
                fields: field_list >>
                opt_multispace >>
                tag!(")") >>
                multispace >>
                (fields)
                )
            ) >>
        tag_no_case!("values") >>
        opt_multispace >>
        data: many1!(
            do_parse!(
                tag!("(") >>
                values: value_list >>
                tag!(")") >>
                opt!(
                    complete!(do_parse!(
                            opt_multispace >>
                            tag!(",") >>
                            opt_multispace >>
                            ()
                    ))
                ) >>
                (values)
            )
        ) >>
        statement_terminator >>
        ({
            // "table AS alias" isn't legal in INSERT statements
            assert!(table.alias.is_none());
            InsertStatement {
                table: table,
                fields: match fields {
                    Some(ref f) =>
                        f.iter()
                         .cloned()
                         .collect(),
                    None =>
                        data[0].iter()
                              .enumerate()
                              .map(|(i, _)| {
                                  Column::from(format!("{}", i).as_str())
                              })
                              .collect(),
                },
                data: data,
                ignore: ignore.is_some(),
            }
        })
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use table::Table;

    #[test]
    fn simple_insert() {
        let qstring = "INSERT INTO users VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("0"), Column::from("1")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    #[test]
    fn complex_insert() {
        let qstring = "INSERT INTO users VALUES (42, 'test', \"test\", CURRENT_TIMESTAMP);";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![
                    Column::from("0"),
                    Column::from("1"),
                    Column::from("2"),
                    Column::from("3"),
                ],
                data: vec![
                    vec![
                        42.into(),
                        "test".into(),
                        "test".into(),
                        Literal::CurrentTimestamp,
                    ],
                ],
                ..Default::default()
            }
        );
    }

    #[test]
    fn insert_with_field_names() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    // Issue #3
    #[test]
    fn insert_without_spaces() {
        let qstring = "INSERT INTO users(id, name) VALUES(42, \"test\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![vec![42.into(), "test".into()]],
                ..Default::default()
            }
        );
    }

    #[test]
    fn multi_insert() {
        let qstring = "INSERT INTO users (id, name) VALUES (42, \"test\"),(21, \"test2\");";

        let res = insertion(qstring.as_bytes());
        assert_eq!(
            res.unwrap().1,
            InsertStatement {
                table: Table::from("users"),
                fields: vec![Column::from("id"), Column::from("name")],
                data: vec![
                    vec![42.into(), "test".into()],
                    vec![21.into(), "test2".into()],
                ],
                ..Default::default()
            }
        );
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
pub mod term;
use core::ops;

/// This is basically a braindead reimplementation of the standard
/// library's `Read` trait. Most of the methods available on the
/// standard lib's `Read` are not yet implemented.
pub trait Read {
    type Error;
    fn read(&mut self, buf: &mut [u8])     -> Result<usize, Self::Error>;
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
}

pub trait Write {
    type Error;
    fn write(&mut self, buf: &[u8])       -> Result<usize, Self::Error>;
}

impl<'a, 'b, E> ops::Shl<&'a [u8]> for &'b mut Write<Error=E> {
    type Output = Self;

    /// Fakes the C++ `<<` operator for IOStreams on Write.
    fn shl(self, _rhs: &'a [u8]) -> Self::Output {
        try!(self.write(_rhs));
        self
    }
}
<commit_msg>[io/mod.rs] Fix issue with missing Debug constraint<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
pub mod term;
use core::ops;
use core::fmt;

/// This is basically a braindead reimplementation of the standard
/// library's `Read` trait. Most of the methods available on the
/// standard lib's `Read` are not yet implemented.
pub trait Read {
    type Error;
    fn read(&mut self, buf: &mut [u8])     -> Result<usize, Self::Error>;
    fn read_all(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
}

pub trait Write {
    type Error;
    fn write(&mut self, buf: &[u8])       -> Result<usize, Self::Error>;
}

impl<'a, 'b, E> ops::Shl<&'a [u8]> for &'b mut Write<Error=E>
where E: fmt::Debug {
    type Output = Self;

    /// Fakes the C++ `<<` operator for IOStreams on Write.
    fn shl(self, _rhs: &'a [u8]) -> Self::Output {
        self.write(_rhs)
            .unwrap();
        self
    }
}
<|endoftext|>


<commit_before>
use ndarray::*;

use super::error::*;
use lapack::c::Layout as Layout_;

pub type Row = usize;
pub type Col = usize;

pub type Row_ = i32;
pub type Col_ = i32;

pub enum Layout {
    C((Row, Col)),
    F((Row, Col)),
}

impl Layout {
    pub fn size(&self) -> (Row, Col) {
        match self {
            &Layout::C(s) => s,
            &Layout::F(s) => s,
        }
    }

    pub fn ffi_size(&self) -> (Row_, Col_) {
        let (n, m) = self.size();
        (n as Row_, m as Col_)
    }

    pub fn ffi_layout(&self) -> Layout_ {
        match self {
            &Layout::C(_) => Layout_::RowMajor,
            &Layout::F(_) => Layout_::ColumnMajor,
        }
    }
}

pub trait AllocatedArray2D {
    type Scalar;
    fn layout(&self) -> Result<Layout>;
    fn square_layout(&self) -> Result<Layout>;
    fn as_allocated(&self) -> Result<&[Self::Scalar]>;
}

impl<A, S> AllocatedArray2D for ArrayBase<S, Ix2>
    where S: Data<Elem = A>
{
    type Scalar = A;

    fn layout(&self) -> Result<Layout> {
        let strides = self.strides();
        if ::std::cmp::min(strides[0], strides[1]) != 1 {
            return Err(StrideError::new(strides[0], strides[1]).into());
        }
        if strides[0] < strides[1] {
            Ok(Layout::C((self.rows(), self.cols())))
        } else {
            Ok(Layout::F((self.rows(), self.cols())))
        }
    }

    fn square_layout(&self) -> Result<Layout> {
        let l = self.layout()?;
        let (n, m) = l.size();
        if n == m {
            Ok(l)
        } else {
            Err(NotSquareError::new(n, m).into())
        }
    }

    fn as_allocated(&self) -> Result<&[A]> {
        let slice = self.as_slice_memory_order().ok_or(MemoryContError::new())?;
        Ok(slice)
    }
}
<commit_msg>Drop 2D<commit_after>
use ndarray::*;

use super::error::*;
use lapack::c::Layout as Layout_;

pub type Row = usize;
pub type Col = usize;

pub type Row_ = i32;
pub type Col_ = i32;

pub enum Layout {
    C((Row, Col)),
    F((Row, Col)),
}

impl Layout {
    pub fn size(&self) -> (Row, Col) {
        match self {
            &Layout::C(s) => s,
            &Layout::F(s) => s,
        }
    }

    pub fn ffi_size(&self) -> (Row_, Col_) {
        let (n, m) = self.size();
        (n as Row_, m as Col_)
    }

    pub fn ffi_layout(&self) -> Layout_ {
        match self {
            &Layout::C(_) => Layout_::RowMajor,
            &Layout::F(_) => Layout_::ColumnMajor,
        }
    }
}

pub trait AllocatedArray {
    type Scalar;
    fn layout(&self) -> Result<Layout>;
    fn square_layout(&self) -> Result<Layout>;
    fn as_allocated(&self) -> Result<&[Self::Scalar]>;
}

impl<A, S> AllocatedArray for ArrayBase<S, Ix2>
    where S: Data<Elem = A>
{
    type Scalar = A;

    fn layout(&self) -> Result<Layout> {
        let strides = self.strides();
        if ::std::cmp::min(strides[0], strides[1]) != 1 {
            return Err(StrideError::new(strides[0], strides[1]).into());
        }
        if strides[0] < strides[1] {
            Ok(Layout::C((self.rows(), self.cols())))
        } else {
            Ok(Layout::F((self.rows(), self.cols())))
        }
    }

    fn square_layout(&self) -> Result<Layout> {
        let l = self.layout()?;
        let (n, m) = l.size();
        if n == m {
            Ok(l)
        } else {
            Err(NotSquareError::new(n, m).into())
        }
    }

    fn as_allocated(&self) -> Result<&[A]> {
        let slice = self.as_slice_memory_order().ok_or(MemoryContError::new())?;
        Ok(slice)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Tasks that are executed by coordinators (short-lived compared to coordinators)
use crate::{
    core_mempool::{CoreMempool, TimelineState, TxnPointer},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{BroadcastError, MempoolSyncMsg},
    shared_mempool::types::{
        notify_subscribers, BatchId, ScheduledBroadcast, SharedMempool, SharedMempoolNotification,
        SubmissionStatusBundle,
    },
    thread_pool::IO_POOL,
    QuorumStoreRequest, QuorumStoreResponse, SubmissionStatus,
};
use anyhow::Result;
use aptos_config::network_id::PeerNetworkId;
use aptos_crypto::HashValue;
use aptos_infallible::{Mutex, RwLock};
use aptos_logger::prelude::*;
use aptos_metrics_core::HistogramTimer;
use aptos_types::{
    mempool_status::{MempoolStatus, MempoolStatusCode},
    on_chain_config::OnChainConfigPayload,
    transaction::SignedTransaction,
    vm_status::DiscardedVMStatus,
};
use consensus_types::common::TransactionSummary;
use futures::{channel::oneshot, stream::FuturesUnordered};
use network::application::interface::NetworkInterface;
use rayon::prelude::*;
use std::{
    cmp,
    collections::HashSet,
    sync::Arc,
    time::{Duration, Instant},
};
use storage_interface::state_view::LatestDbStateCheckpointView;
use tokio::runtime::Handle;
use vm_validator::vm_validator::{get_account_sequence_number, TransactionValidation};

// ============================== //
//  broadcast_coordinator tasks  //
// ============================== //

/// Attempts broadcast to `peer` and schedules the next broadcast.
pub(crate) async fn execute_broadcast<V>(
    peer: PeerNetworkId,
    backoff: bool,
    smp: &mut SharedMempool<V>,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    executor: Handle,
) where
    V: TransactionValidation,
{
    let network_interface = &smp.network_interface.clone();
    // If there's no connection, don't bother to broadcast
    if network_interface.app_data().read(&peer).is_some() {
        if let Err(err) = network_interface
            .execute_broadcast(peer, backoff, smp)
            .await
        {
            match err {
                BroadcastError::NetworkError(peer, error) => error!(LogSchema::event_log(
                    LogEntry::BroadcastTransaction,
                    LogEvent::NetworkSendFail
                )
                .peer(&peer)
                .error(&error)),
                _ => {
                    trace!("{:?}", err)
                }
            }
        }
    } else {
        // Drop the scheduled broadcast, we're not connected anymore
        return;
    }
    let schedule_backoff = network_interface.is_backoff_mode(&peer);

    let interval_ms = if schedule_backoff {
        smp.config.shared_mempool_backoff_interval_ms
    } else {
        smp.config.shared_mempool_tick_interval_ms
    };

    scheduled_broadcasts.push(ScheduledBroadcast::new(
        Instant::now() + Duration::from_millis(interval_ms),
        peer,
        schedule_backoff,
        executor,
    ))
}

// =============================== //
// Tasks processing txn submission //
// =============================== //

/// Processes transactions directly submitted by client.
pub(crate) async fn process_client_transaction_submission<V>(
    smp: SharedMempool<V>,
    transaction: SignedTransaction,
    callback: oneshot::Sender<Result<SubmissionStatus>>,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_txn_submit_latency_timer_client();
    let ineligible_for_broadcast =
        !smp.broadcast_within_validator_network() && smp.network_interface.is_validator();
    let timeline_state = if ineligible_for_broadcast {
        TimelineState::NonQualified
    } else {
        TimelineState::NotReady
    };
    let statuses = process_incoming_transactions(&smp, vec![transaction], timeline_state);
    log_txn_process_results(&statuses, None);

    if let Some(status) = statuses.first() {
        if callback.send(Ok(status.1.clone())).is_err() {
            error!(LogSchema::event_log(
                LogEntry::JsonRpc,
                LogEvent::CallbackFail
            ));
            counters::CLIENT_CALLBACK_FAIL.inc();
        }
    }
}

/// Processes get transaction by hash request by client.
pub(crate) async fn process_client_get_transaction<V>(
    smp: SharedMempool<V>,
    hash: HashValue,
    callback: oneshot::Sender<Option<SignedTransaction>>,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_get_txn_latency_timer_client();
    let txn = smp.mempool.lock().get_by_hash(hash);

    if callback.send(txn).is_err() {
        error!(LogSchema::event_log(
            LogEntry::GetTransaction,
            LogEvent::CallbackFail
        ));
        counters::CLIENT_CALLBACK_FAIL.inc();
    }
}

/// Processes transactions from other nodes.
pub(crate) async fn process_transaction_broadcast<V>(
    smp: SharedMempool<V>,
    transactions: Vec<SignedTransaction>,
    request_id: BatchId,
    timeline_state: TimelineState,
    peer: PeerNetworkId,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_txn_submit_latency_timer(peer.network_id());
    let results = process_incoming_transactions(&smp, transactions, timeline_state);
    log_txn_process_results(&results, Some(peer));

    let ack_response = gen_ack_response(request_id, results, &peer);
    let network_sender = smp.network_interface.sender();

    // Respond to the peer with an ack. Note: ack response messages should be
    // small enough that they always fit within the maximum network message
    // size, so there's no need to check them here.
    if let Err(e) = network_sender.send_to(peer, ack_response) {
        counters::network_send_fail_inc(counters::ACK_TXNS);
        error!(
            LogSchema::event_log(LogEntry::BroadcastACK, LogEvent::NetworkSendFail)
                .peer(&peer)
                .error(&e.into())
        );
        return;
    }
    notify_subscribers(SharedMempoolNotification::ACK, &smp.subscribers);
}

/// If `MempoolIsFull` on any of the transactions, provide backpressure to the downstream peer.
fn gen_ack_response(
    request_id: BatchId,
    results: Vec<SubmissionStatusBundle>,
    peer: &PeerNetworkId,
) -> MempoolSyncMsg {
    let mut backoff_and_retry = false;
    for (_, (mempool_status, _)) in results.into_iter() {
        if mempool_status.code == MempoolStatusCode::MempoolIsFull {
            backoff_and_retry = true;
            break;
        }
    }

    update_ack_counter(
        peer,
        counters::SENT_LABEL,
        backoff_and_retry,
        backoff_and_retry,
    );
    MempoolSyncMsg::BroadcastTransactionsResponse {
        request_id,
        retry: backoff_and_retry,
        backoff: backoff_and_retry,
    }
}

pub(crate) fn update_ack_counter(
    peer: &PeerNetworkId,
    direction_label: &str,
    retry: bool,
    backoff: bool,
) {
    if retry {
        counters::shared_mempool_ack_inc(
            peer.network_id(),
            direction_label,
            counters::RETRY_BROADCAST_LABEL,
        );
    }
    if backoff {
        counters::shared_mempool_ack_inc(
            peer.network_id(),
            direction_label,
            counters::BACKPRESSURE_BROADCAST_LABEL,
        );
    }
}

/// Submits a list of SignedTransaction to the local mempool
/// and returns a vector containing AdmissionControlStatus.
pub(crate) fn process_incoming_transactions<V>(
    smp: &SharedMempool<V>,
    transactions: Vec<SignedTransaction>,
    timeline_state: TimelineState,
) -> Vec<SubmissionStatusBundle>
where
    V: TransactionValidation,
{
    let mut statuses = vec![];

    let start_storage_read = Instant::now();
    let state_view = smp
        .db
        .latest_state_checkpoint_view()
        .expect("Failed to get latest state checkpoint view.");

    // Track latency: fetching seq number
    let seq_numbers = IO_POOL.install(|| {
        transactions
            .par_iter()
            .map(|t| {
                get_account_sequence_number(&state_view, t.sender()).map_err(|e| {
                    error!(LogSchema::new(LogEntry::DBError).error(&e));
                    counters::DB_ERROR.inc();
                    e
                })
            })
            .collect::<Vec<_>>()
    });
    // Track latency for storage read fetching sequence number
    let storage_read_latency = start_storage_read.elapsed();
    counters::PROCESS_TXN_BREAKDOWN_LATENCY
        .with_label_values(&[counters::FETCH_SEQ_NUM_LABEL])
        .observe(storage_read_latency.as_secs_f64() / transactions.len() as f64);

    let transactions: Vec<_> = transactions
        .into_iter()
        .enumerate()
        .filter_map(|(idx, t)| {
            if let Ok(sequence_info) = seq_numbers[idx] {
                if t.sequence_number() >= sequence_info.min_seq() {
                    return Some((t, sequence_info));
                } else {
                    statuses.push((
                        t,
                        (
                            MempoolStatus::new(MempoolStatusCode::VmError),
                            Some(DiscardedVMStatus::SEQUENCE_NUMBER_TOO_OLD),
                        ),
                    ));
                }
            } else {
                // Failed to get transaction
                statuses.push((
                    t,
                    (
                        MempoolStatus::new(MempoolStatusCode::VmError),
                        Some(DiscardedVMStatus::RESOURCE_DOES_NOT_EXIST),
                    ),
                ));
            }
            None
        })
        .collect();

    // Track latency: VM validation
    let vm_validation_timer = counters::PROCESS_TXN_BREAKDOWN_LATENCY
        .with_label_values(&[counters::VM_VALIDATION_LABEL])
        .start_timer();
    let validation_results = transactions
        .iter()
        .map(|t| smp.validator.read().validate_transaction(t.0.clone()))
        .collect::<Vec<_>>();
    vm_validation_timer.stop_and_record();
    {
        let mut mempool = smp.mempool.lock();
        for (idx, (transaction, sequence_info)) in transactions.into_iter().enumerate() {
            if let Ok(validation_result) = &validation_results[idx] {
                match validation_result.status() {
                    None => {
                        let ranking_score = validation_result.score();
                        let mempool_status = mempool.add_txn(
                            transaction.clone(),
                            ranking_score,
                            sequence_info,
                            timeline_state,
                        );
                        statuses.push((transaction, (mempool_status, None)));
                    }
                    Some(validation_status) => {
                        statuses.push((
                            transaction.clone(),
                            (
                                MempoolStatus::new(MempoolStatusCode::VmError),
                                Some(validation_status),
                            ),
                        ));
                    }
                }
            }
        }
    }
    notify_subscribers(SharedMempoolNotification::NewTransactions, &smp.subscribers);
    statuses
}

fn log_txn_process_results(results: &[SubmissionStatusBundle], sender: Option<PeerNetworkId>) {
    let network = match sender {
        Some(peer) => peer.network_id().to_string(),
        None => counters::CLIENT_LABEL.to_string(),
    };
    for (txn, (mempool_status, maybe_vm_status)) in results.iter() {
        if let Some(vm_status) = maybe_vm_status {
            trace!(
                SecurityEvent::InvalidTransactionMempool,
                failed_transaction = txn,
                vm_status = vm_status,
                sender = sender,
            );
            counters::shared_mempool_transactions_processed_inc(
                counters::VM_VALIDATION_LABEL,
                &network,
            );
            continue;
        }
        match mempool_status.code {
            MempoolStatusCode::Accepted => counters::shared_mempool_transactions_processed_inc(
                counters::SUCCESS_LABEL,
                &network,
            ),
            _ => counters::shared_mempool_transactions_processed_inc(
                &mempool_status.code.to_string(),
                &network,
            ),
        }
    }
}

// ================================= //
// intra-node communication handlers //
// ================================= //

/// Only applies to Validators. Either provides transactions to consensus [`GetBlockRequest`] or
/// handles rejecting transactions [`RejectNotification`]
pub(crate) fn process_quorum_store_request<V: TransactionValidation>(
    smp: &SharedMempool<V>,
    req: QuorumStoreRequest,
) {
    // Start latency timer
    let start_time = Instant::now();
    debug!(LogSchema::event_log(LogEntry::QuorumStore, LogEvent::Received).quorum_store_msg(&req));

    let (resp, callback, counter_label) = match req {
        QuorumStoreRequest::GetBatchRequest(max_txns, max_bytes, transactions, callback) => {
            let exclude_transactions: HashSet<TxnPointer> = transactions
                .iter()
                .map(|txn| (txn.sender, txn.sequence_number))
                .collect();
            let txns;
            {
                let mut mempool = smp.mempool.lock();
                // gc before pulling block as extra protection against txns that may expire in consensus
                // Note: this gc operation relies on the fact that consensus uses the system time to determine block timestamp
                let curr_time = aptos_infallible::duration_since_epoch();
                mempool.gc_by_expiration_time(curr_time);
                let max_txns = cmp::max(max_txns, 1);
                txns = mempool.get_batch(max_txns, max_bytes, exclude_transactions);
            }
            counters::mempool_service_transactions(counters::GET_BLOCK_LABEL, txns.len());

            (
                QuorumStoreResponse::GetBatchResponse(txns),
                callback,
                counters::GET_BLOCK_LABEL,
            )
        }
        QuorumStoreRequest::RejectNotification(transactions, callback) => {
            counters::mempool_service_transactions(
                counters::COMMIT_CONSENSUS_LABEL,
                transactions.len(),
            );
            process_committed_transactions(&smp.mempool, transactions, 0, true);
            (
                QuorumStoreResponse::CommitResponse(),
                callback,
                counters::COMMIT_CONSENSUS_LABEL,
            )
        }
    };
    // Send back to callback
    let result = if callback.send(Ok(resp)).is_err() {
        error!(LogSchema::event_log(
            LogEntry::QuorumStore,
            LogEvent::CallbackFail
        ));
        counters::REQUEST_FAIL_LABEL
    } else {
        counters::REQUEST_SUCCESS_LABEL
    };
    let latency = start_time.elapsed();
    counters::mempool_service_latency(counter_label, result, latency);
}

/// Remove transactions that are committed (or rejected) so that we can stop broadcasting them.
pub(crate) fn process_committed_transactions(
    mempool: &Mutex<CoreMempool>,
    transactions: Vec<TransactionSummary>,
    block_timestamp_usecs: u64,
    is_rejected: bool,
) {
    let mut pool = mempool.lock();

    for transaction in transactions {
        pool.remove_transaction(
            &transaction.sender,
            transaction.sequence_number,
            is_rejected,
        );
    }

    if block_timestamp_usecs > 0 {
        pool.gc_by_expiration_time(Duration::from_micros(block_timestamp_usecs));
    }
}

/// Processes on-chain reconfiguration notifications.  Restarts validator with the new info.
pub(crate) async fn process_config_update<V>(
    config_update: OnChainConfigPayload,
    validator: Arc<RwLock<V>>,
) where
    V: TransactionValidation,
{
    info!(
        LogSchema::event_log(LogEntry::ReconfigUpdate, LogEvent::Process)
            .reconfig_update(config_update.clone())
    );

    if let Err(e) = validator.write().restart(config_update) {
        counters::VM_RECONFIG_UPDATE_FAIL_COUNT.inc();
        error!(LogSchema::event_log(LogEntry::ReconfigUpdate, LogEvent::VMUpdateFail).error(&e));
    }
}
<commit_msg>[mempool] handle when validate_transaction returns an error (#4135)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Tasks that are executed by coordinators (short-lived compared to coordinators)
use crate::{
    core_mempool::{CoreMempool, TimelineState, TxnPointer},
    counters,
    logging::{LogEntry, LogEvent, LogSchema},
    network::{BroadcastError, MempoolSyncMsg},
    shared_mempool::types::{
        notify_subscribers, BatchId, ScheduledBroadcast, SharedMempool, SharedMempoolNotification,
        SubmissionStatusBundle,
    },
    thread_pool::IO_POOL,
    QuorumStoreRequest, QuorumStoreResponse, SubmissionStatus,
};
use anyhow::Result;
use aptos_config::network_id::PeerNetworkId;
use aptos_crypto::HashValue;
use aptos_infallible::{Mutex, RwLock};
use aptos_logger::prelude::*;
use aptos_metrics_core::HistogramTimer;
use aptos_types::{
    mempool_status::{MempoolStatus, MempoolStatusCode},
    on_chain_config::OnChainConfigPayload,
    transaction::SignedTransaction,
    vm_status::DiscardedVMStatus,
};
use consensus_types::common::TransactionSummary;
use futures::{channel::oneshot, stream::FuturesUnordered};
use network::application::interface::NetworkInterface;
use rayon::prelude::*;
use std::{
    cmp,
    collections::HashSet,
    sync::Arc,
    time::{Duration, Instant},
};
use storage_interface::state_view::LatestDbStateCheckpointView;
use tokio::runtime::Handle;
use vm_validator::vm_validator::{get_account_sequence_number, TransactionValidation};

// ============================== //
//  broadcast_coordinator tasks  //
// ============================== //

/// Attempts broadcast to `peer` and schedules the next broadcast.
pub(crate) async fn execute_broadcast<V>(
    peer: PeerNetworkId,
    backoff: bool,
    smp: &mut SharedMempool<V>,
    scheduled_broadcasts: &mut FuturesUnordered<ScheduledBroadcast>,
    executor: Handle,
) where
    V: TransactionValidation,
{
    let network_interface = &smp.network_interface.clone();
    // If there's no connection, don't bother to broadcast
    if network_interface.app_data().read(&peer).is_some() {
        if let Err(err) = network_interface
            .execute_broadcast(peer, backoff, smp)
            .await
        {
            match err {
                BroadcastError::NetworkError(peer, error) => error!(LogSchema::event_log(
                    LogEntry::BroadcastTransaction,
                    LogEvent::NetworkSendFail
                )
                .peer(&peer)
                .error(&error)),
                _ => {
                    trace!("{:?}", err)
                }
            }
        }
    } else {
        // Drop the scheduled broadcast, we're not connected anymore
        return;
    }
    let schedule_backoff = network_interface.is_backoff_mode(&peer);

    let interval_ms = if schedule_backoff {
        smp.config.shared_mempool_backoff_interval_ms
    } else {
        smp.config.shared_mempool_tick_interval_ms
    };

    scheduled_broadcasts.push(ScheduledBroadcast::new(
        Instant::now() + Duration::from_millis(interval_ms),
        peer,
        schedule_backoff,
        executor,
    ))
}

// =============================== //
// Tasks processing txn submission //
// =============================== //

/// Processes transactions directly submitted by client.
pub(crate) async fn process_client_transaction_submission<V>(
    smp: SharedMempool<V>,
    transaction: SignedTransaction,
    callback: oneshot::Sender<Result<SubmissionStatus>>,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_txn_submit_latency_timer_client();
    let ineligible_for_broadcast =
        !smp.broadcast_within_validator_network() && smp.network_interface.is_validator();
    let timeline_state = if ineligible_for_broadcast {
        TimelineState::NonQualified
    } else {
        TimelineState::NotReady
    };
    let statuses = process_incoming_transactions(&smp, vec![transaction], timeline_state);
    log_txn_process_results(&statuses, None);

    if let Some(status) = statuses.first() {
        if callback.send(Ok(status.1.clone())).is_err() {
            error!(LogSchema::event_log(
                LogEntry::JsonRpc,
                LogEvent::CallbackFail
            ));
            counters::CLIENT_CALLBACK_FAIL.inc();
        }
    }
}

/// Processes get transaction by hash request by client.
pub(crate) async fn process_client_get_transaction<V>(
    smp: SharedMempool<V>,
    hash: HashValue,
    callback: oneshot::Sender<Option<SignedTransaction>>,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_get_txn_latency_timer_client();
    let txn = smp.mempool.lock().get_by_hash(hash);

    if callback.send(txn).is_err() {
        error!(LogSchema::event_log(
            LogEntry::GetTransaction,
            LogEvent::CallbackFail
        ));
        counters::CLIENT_CALLBACK_FAIL.inc();
    }
}

/// Processes transactions from other nodes.
pub(crate) async fn process_transaction_broadcast<V>(
    smp: SharedMempool<V>,
    transactions: Vec<SignedTransaction>,
    request_id: BatchId,
    timeline_state: TimelineState,
    peer: PeerNetworkId,
    timer: HistogramTimer,
) where
    V: TransactionValidation,
{
    timer.stop_and_record();
    let _timer = counters::process_txn_submit_latency_timer(peer.network_id());
    let results = process_incoming_transactions(&smp, transactions, timeline_state);
    log_txn_process_results(&results, Some(peer));

    let ack_response = gen_ack_response(request_id, results, &peer);
    let network_sender = smp.network_interface.sender();

    // Respond to the peer with an ack. Note: ack response messages should be
    // small enough that they always fit within the maximum network message
    // size, so there's no need to check them here.
    if let Err(e) = network_sender.send_to(peer, ack_response) {
        counters::network_send_fail_inc(counters::ACK_TXNS);
        error!(
            LogSchema::event_log(LogEntry::BroadcastACK, LogEvent::NetworkSendFail)
                .peer(&peer)
                .error(&e.into())
        );
        return;
    }
    notify_subscribers(SharedMempoolNotification::ACK, &smp.subscribers);
}

/// If `MempoolIsFull` on any of the transactions, provide backpressure to the downstream peer.
fn gen_ack_response(
    request_id: BatchId,
    results: Vec<SubmissionStatusBundle>,
    peer: &PeerNetworkId,
) -> MempoolSyncMsg {
    let mut backoff_and_retry = false;
    for (_, (mempool_status, _)) in results.into_iter() {
        if mempool_status.code == MempoolStatusCode::MempoolIsFull {
            backoff_and_retry = true;
            break;
        }
    }

    update_ack_counter(
        peer,
        counters::SENT_LABEL,
        backoff_and_retry,
        backoff_and_retry,
    );
    MempoolSyncMsg::BroadcastTransactionsResponse {
        request_id,
        retry: backoff_and_retry,
        backoff: backoff_and_retry,
    }
}

pub(crate) fn update_ack_counter(
    peer: &PeerNetworkId,
    direction_label: &str,
    retry: bool,
    backoff: bool,
) {
    if retry {
        counters::shared_mempool_ack_inc(
            peer.network_id(),
            direction_label,
            counters::RETRY_BROADCAST_LABEL,
        );
    }
    if backoff {
        counters::shared_mempool_ack_inc(
            peer.network_id(),
            direction_label,
            counters::BACKPRESSURE_BROADCAST_LABEL,
        );
    }
}

/// Submits a list of SignedTransaction to the local mempool
/// and returns a vector containing AdmissionControlStatus.
pub(crate) fn process_incoming_transactions<V>(
    smp: &SharedMempool<V>,
    transactions: Vec<SignedTransaction>,
    timeline_state: TimelineState,
) -> Vec<SubmissionStatusBundle>
where
    V: TransactionValidation,
{
    let mut statuses = vec![];

    let start_storage_read = Instant::now();
    let state_view = smp
        .db
        .latest_state_checkpoint_view()
        .expect("Failed to get latest state checkpoint view.");

    // Track latency: fetching seq number
    let seq_numbers = IO_POOL.install(|| {
        transactions
            .par_iter()
            .map(|t| {
                get_account_sequence_number(&state_view, t.sender()).map_err(|e| {
                    error!(LogSchema::new(LogEntry::DBError).error(&e));
                    counters::DB_ERROR.inc();
                    e
                })
            })
            .collect::<Vec<_>>()
    });
    // Track latency for storage read fetching sequence number
    let storage_read_latency = start_storage_read.elapsed();
    counters::PROCESS_TXN_BREAKDOWN_LATENCY
        .with_label_values(&[counters::FETCH_SEQ_NUM_LABEL])
        .observe(storage_read_latency.as_secs_f64() / transactions.len() as f64);

    let transactions: Vec<_> = transactions
        .into_iter()
        .enumerate()
        .filter_map(|(idx, t)| {
            if let Ok(sequence_info) = seq_numbers[idx] {
                if t.sequence_number() >= sequence_info.min_seq() {
                    return Some((t, sequence_info));
                } else {
                    statuses.push((
                        t,
                        (
                            MempoolStatus::new(MempoolStatusCode::VmError),
                            Some(DiscardedVMStatus::SEQUENCE_NUMBER_TOO_OLD),
                        ),
                    ));
                }
            } else {
                // Failed to get transaction
                statuses.push((
                    t,
                    (
                        MempoolStatus::new(MempoolStatusCode::VmError),
                        Some(DiscardedVMStatus::RESOURCE_DOES_NOT_EXIST),
                    ),
                ));
            }
            None
        })
        .collect();

    // Track latency: VM validation
    let vm_validation_timer = counters::PROCESS_TXN_BREAKDOWN_LATENCY
        .with_label_values(&[counters::VM_VALIDATION_LABEL])
        .start_timer();
    let validation_results = transactions
        .iter()
        .map(|t| smp.validator.read().validate_transaction(t.0.clone()))
        .collect::<Vec<_>>();
    vm_validation_timer.stop_and_record();
    {
        let mut mempool = smp.mempool.lock();
        for (idx, (transaction, sequence_info)) in transactions.into_iter().enumerate() {
            if let Ok(validation_result) = &validation_results[idx] {
                match validation_result.status() {
                    None => {
                        let ranking_score = validation_result.score();
                        let mempool_status = mempool.add_txn(
                            transaction.clone(),
                            ranking_score,
                            sequence_info,
                            timeline_state,
                        );
                        statuses.push((transaction, (mempool_status, None)));
                    }
                    Some(validation_status) => {
                        statuses.push((
                            transaction.clone(),
                            (
                                MempoolStatus::new(MempoolStatusCode::VmError),
                                Some(validation_status),
                            ),
                        ));
                    }
                }
            } else {
                statuses.push((
                    transaction.clone(),
                    (
                        MempoolStatus::new(MempoolStatusCode::VmError),
                        Some(DiscardedVMStatus::UNKNOWN_STATUS),
                    ),
                ));
            }
        }
    }
    notify_subscribers(SharedMempoolNotification::NewTransactions, &smp.subscribers);
    statuses
}

fn log_txn_process_results(results: &[SubmissionStatusBundle], sender: Option<PeerNetworkId>) {
    let network = match sender {
        Some(peer) => peer.network_id().to_string(),
        None => counters::CLIENT_LABEL.to_string(),
    };
    for (txn, (mempool_status, maybe_vm_status)) in results.iter() {
        if let Some(vm_status) = maybe_vm_status {
            trace!(
                SecurityEvent::InvalidTransactionMempool,
                failed_transaction = txn,
                vm_status = vm_status,
                sender = sender,
            );
            counters::shared_mempool_transactions_processed_inc(
                counters::VM_VALIDATION_LABEL,
                &network,
            );
            continue;
        }
        match mempool_status.code {
            MempoolStatusCode::Accepted => counters::shared_mempool_transactions_processed_inc(
                counters::SUCCESS_LABEL,
                &network,
            ),
            _ => counters::shared_mempool_transactions_processed_inc(
                &mempool_status.code.to_string(),
                &network,
            ),
        }
    }
}

// ================================= //
// intra-node communication handlers //
// ================================= //

/// Only applies to Validators. Either provides transactions to consensus [`GetBlockRequest`] or
/// handles rejecting transactions [`RejectNotification`]
pub(crate) fn process_quorum_store_request<V: TransactionValidation>(
    smp: &SharedMempool<V>,
    req: QuorumStoreRequest,
) {
    // Start latency timer
    let start_time = Instant::now();
    debug!(LogSchema::event_log(LogEntry::QuorumStore, LogEvent::Received).quorum_store_msg(&req));

    let (resp, callback, counter_label) = match req {
        QuorumStoreRequest::GetBatchRequest(max_txns, max_bytes, transactions, callback) => {
            let exclude_transactions: HashSet<TxnPointer> = transactions
                .iter()
                .map(|txn| (txn.sender, txn.sequence_number))
                .collect();
            let txns;
            {
                let mut mempool = smp.mempool.lock();
                // gc before pulling block as extra protection against txns that may expire in consensus
                // Note: this gc operation relies on the fact that consensus uses the system time to determine block timestamp
                let curr_time = aptos_infallible::duration_since_epoch();
                mempool.gc_by_expiration_time(curr_time);
                let max_txns = cmp::max(max_txns, 1);
                txns = mempool.get_batch(max_txns, max_bytes, exclude_transactions);
            }
            counters::mempool_service_transactions(counters::GET_BLOCK_LABEL, txns.len());

            (
                QuorumStoreResponse::GetBatchResponse(txns),
                callback,
                counters::GET_BLOCK_LABEL,
            )
        }
        QuorumStoreRequest::RejectNotification(transactions, callback) => {
            counters::mempool_service_transactions(
                counters::COMMIT_CONSENSUS_LABEL,
                transactions.len(),
            );
            process_committed_transactions(&smp.mempool, transactions, 0, true);
            (
                QuorumStoreResponse::CommitResponse(),
                callback,
                counters::COMMIT_CONSENSUS_LABEL,
            )
        }
    };
    // Send back to callback
    let result = if callback.send(Ok(resp)).is_err() {
        error!(LogSchema::event_log(
            LogEntry::QuorumStore,
            LogEvent::CallbackFail
        ));
        counters::REQUEST_FAIL_LABEL
    } else {
        counters::REQUEST_SUCCESS_LABEL
    };
    let latency = start_time.elapsed();
    counters::mempool_service_latency(counter_label, result, latency);
}

/// Remove transactions that are committed (or rejected) so that we can stop broadcasting them.
pub(crate) fn process_committed_transactions(
    mempool: &Mutex<CoreMempool>,
    transactions: Vec<TransactionSummary>,
    block_timestamp_usecs: u64,
    is_rejected: bool,
) {
    let mut pool = mempool.lock();

    for transaction in transactions {
        pool.remove_transaction(
            &transaction.sender,
            transaction.sequence_number,
            is_rejected,
        );
    }

    if block_timestamp_usecs > 0 {
        pool.gc_by_expiration_time(Duration::from_micros(block_timestamp_usecs));
    }
}

/// Processes on-chain reconfiguration notifications.  Restarts validator with the new info.
pub(crate) async fn process_config_update<V>(
    config_update: OnChainConfigPayload,
    validator: Arc<RwLock<V>>,
) where
    V: TransactionValidation,
{
    info!(
        LogSchema::event_log(LogEntry::ReconfigUpdate, LogEvent::Process)
            .reconfig_update(config_update.clone())
    );

    if let Err(e) = validator.write().restart(config_update) {
        counters::VM_RECONFIG_UPDATE_FAIL_COUNT.inc();
        error!(LogSchema::event_log(LogEntry::ReconfigUpdate, LogEvent::VMUpdateFail).error(&e));
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// error-pattern: An error message for you

fn main() -> Result<(), &'static str> {
    Err("An error message for you")
}
<commit_msg>add `failure-status: 1` to the test<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// error-pattern: An error message for you
// failure-status: 1

fn main() -> Result<(), &'static str> {
    Err("An error message for you")
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::str::FromStr;
use datatable::*;

pub struct Loader<'a> {
    pub file: &'a str,
    pub delimiter: char,
}

impl<'a> Loader<'a> {
    /// Load the file from the loader with given delimiter.
    ///
    /// Pretty rudimentary with poor error handling.
    pub fn load_file(self) -> Result<DataTable, io::Error> {
        let f = try!(File::open(self.file));
        let reader = BufReader::new(f);

        let mut table = DataTable::empty();

        // Should handle header here

        let mut lines = reader.lines();

        if let Some(line) = lines.next() {
            let line = try!(line);
            let values = line.split(self.delimiter);

            for val in values {
                let mut column = DataCols::<f64>::empty();
                // Unwrap and panic for now.
                // Should handle more carefully in future.
                column.data.push(f64::from_str(val).unwrap());

                table.data_cols.push(column);
            }
        }

        for line in lines {
            let line = try!(line);
            let values = line.split(self.delimiter);

            for (i, val) in values.enumerate() {

                // Unwrap and panic for now.
                // Should handle more carefully in future.
                let val = f64::from_str(val).unwrap();
                table.data_cols[i].data.push(val);
            }
        }

        Ok(table)
    }
}

pub fn load_file(file: &str) -> DataTable {
    let loader = Loader {
        file: file,
        delimiter: ',',
    };

    loader.load_file().unwrap()

}
<commit_msg>A little more error handling<commit_after>use std::io;
use std::io::prelude::*;
use std::io::{BufReader, Error, ErrorKind};
use std::fs::File;
use std::str::FromStr;
use datatable::*;

pub struct Loader<'a> {
    pub file: &'a str,
    pub delimiter: char,
}

impl<'a> Loader<'a> {
    /// Load the file from the loader with given delimiter.
    ///
    /// Pretty rudimentary with poor error handling.
    ///
    /// # Panics
    ///
    /// - The input data is not a float.
    ///
    /// # Failures
    ///
    /// - The input data is malformed (missing data, non-uniform rows etc.)
    pub fn load_file(self) -> Result<DataTable, io::Error> {
        let f = try!(File::open(self.file));
        let reader = BufReader::new(f);

        let mut table = DataTable::empty();

        // Should handle header here

        let mut lines = reader.lines();

        if let Some(line) = lines.next() {
            let line = try!(line);
            let values = line.split(self.delimiter);

            for val in values {
                let mut column = DataCols::<f64>::empty();
                // Unwrap and panic for now.
                // Should handle more carefully in future.
                column.data.push(f64::from_str(val).unwrap());

                table.data_cols.push(column);
            }
        }

        for line in lines {
            let line = try!(line);
            let values = line.split(self.delimiter);

            let mut idx = 0usize;

            for (i, val) in values.enumerate() {
                idx = i;
                if idx > table.cols() {
                    return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format on."));
                }
                // Unwrap and panic for now.
                // Should handle more carefully in future.
                let val = f64::from_str(val).unwrap();
                table.data_cols[idx].data.push(val);
            }

            if idx != table.cols()-1 {
                return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format."));
            }
        }

        Ok(table)
    }
}

/// Load the specified file to a DataTable.
///
/// # Examples
///
/// ```no_run
/// use rusty_data::loader::load_file;
///
/// let table = load_file("path/to/file.data");
/// ```
pub fn load_file(file: &str) -> DataTable {
    let loader = Loader {
        file: file,
        delimiter: ',',
    };

    loader.load_file().unwrap()

}
<|endoftext|>


<commit_before>/// Compose multiple state machines into single type
///
/// Composition requires two types: the state machine itself and Seed which
/// is used to create children state machines.
///
/// Mostly because of limitations of Rust macro system composition only works
/// on concrete context type.
///
/// # Example
/// ```ignore
/// rotor_compose!{
///     pub enum Fsm/Seed<Context> {
///         Http(HttpMachine)
///         Dns(DnsMachine)
///     }
/// }
/// ```
///
/// This creates a an `Fsm` state machine type which is enum with two options.
/// And `Seed` state machine type, which is also enum with same option names
/// but uses `<HttpMachine as rotor::Machine>::Seed` for the wrapped type.
#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        enum $cname {
            $( $iname (<$itype as $crate::Machine>::Seed), )*
        }
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> Response<Self, $crate::Void>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope)
                            .map($name::$iname, |x| unreachable(x)),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<commit_msg>Fix namespacing in macro<commit_after>/// Compose multiple state machines into single type
///
/// Composition requires two types: the state machine itself and Seed which
/// is used to create children state machines.
///
/// Mostly because of limitations of Rust macro system composition only works
/// on concrete context type.
///
/// # Example
/// ```ignore
/// rotor_compose!{
///     pub enum Fsm/Seed<Context> {
///         Http(HttpMachine)
///         Dns(DnsMachine)
///     }
/// }
/// ```
///
/// This creates a an `Fsm` state machine type which is enum with two options.
/// And `Seed` state machine type, which is also enum with same option names
/// but uses `<HttpMachine as rotor::Machine>::Seed` for the wrapped type.
#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        enum $cname {
            $( $iname (<$itype as $crate::Machine>::Seed), )*
        }
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, $crate::Void>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope)
                            .map($name::$iname, |x| unreachable(x)),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![macro_use]

macro_rules! debug(
    ($($args:tt)*) => (
        if cfg!(not(ndebug)) {
            let module_path: String = module_path!().to_string();
            let line: String = line!().to_string();
            let message: String = format_args!($($args)*).to_string();
            println!("({}:{}) {}", module_path, line, message);
        }
    )
);

#[cfg(feature = "valgrind")]
pub mod valgrind {
    extern crate vgrs;
    pub use self::vgrs::memcheck::{malloclike_block, freelike_block, do_quick_leak_check, count_leaks};
}

#[cfg(not(feature = "valgrind"))]
#[allow(unused_variables)]
pub mod valgrind {
    pub struct LeakCount {
        pub leaked: usize,
    }
    pub unsafe fn malloclike_block(addr: *const (), size: usize, redzone: usize, is_zeroed: bool) { }
    pub unsafe fn freelike_block(addr: *const (), redzone: usize) { }
    pub unsafe fn do_quick_leak_check() { }
    pub unsafe fn count_leaks() -> LeakCount { return  LeakCount { leaked: 0 } }
}

macro_rules! valgrind_malloclike(
    ($addr:expr, $size:expr) => (
        if cfg!(feature = "valgrind") {
            unsafe{
                debug!("Mark object {:p} with malloclike_block for valgrind", $addr);
                ::macros::valgrind::malloclike_block($addr as *const (), $size, 0, true);
            }
        }
    )
);

macro_rules! valgrind_freelike(
    ($addr:expr) => (
        if cfg!(feature = "valgrind") {
            unsafe{
                debug!("Mark object {:p} with freelike_block for valgrind", $addr);
                ::macros:: valgrind::freelike_block($addr as *const (), 0);
            }
        }
    )
);

macro_rules! valgrind_assert_no_leaks(
    () => (
        if cfg!(feature = "valgrind") {
            unsafe{
                if cfg!(not(ndebug)) {
                    ::macros::valgrind::do_quick_leak_check();
                }
                let leak_count = ::macros::valgrind::count_leaks();
                assert!(leak_count.leaked == 0, "Valgrind reported leaked memory");
            }
        }
    )
);
<commit_msg>Remove weird hack in macros.rs<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![macro_use]

macro_rules! debug(
    ($($args:tt)*) => (
        if cfg!(not(ndebug)) {
            println!("({}:{}) {}", module_path!(), line!(), format_args!($($args)*));
        }
    )
);

#[cfg(feature = "valgrind")]
pub mod valgrind {
    extern crate vgrs;
    pub use self::vgrs::memcheck::{malloclike_block, freelike_block, do_quick_leak_check, count_leaks};
}

#[cfg(not(feature = "valgrind"))]
#[allow(unused_variables)]
pub mod valgrind {
    pub struct LeakCount {
        pub leaked: usize,
    }
    pub unsafe fn malloclike_block(addr: *const (), size: usize, redzone: usize, is_zeroed: bool) { }
    pub unsafe fn freelike_block(addr: *const (), redzone: usize) { }
    pub unsafe fn do_quick_leak_check() { }
    pub unsafe fn count_leaks() -> LeakCount { return  LeakCount { leaked: 0 } }
}

macro_rules! valgrind_malloclike(
    ($addr:expr, $size:expr) => (
        if cfg!(feature = "valgrind") {
            unsafe{
                debug!("Mark object {:p} with malloclike_block for valgrind", $addr);
                ::macros::valgrind::malloclike_block($addr as *const (), $size, 0, true);
            }
        }
    )
);

macro_rules! valgrind_freelike(
    ($addr:expr) => (
        if cfg!(feature = "valgrind") {
            unsafe{
                debug!("Mark object {:p} with freelike_block for valgrind", $addr);
                ::macros:: valgrind::freelike_block($addr as *const (), 0);
            }
        }
    )
);

macro_rules! valgrind_assert_no_leaks(
    () => (
        if cfg!(feature = "valgrind") {
            unsafe{
                if cfg!(not(ndebug)) {
                    ::macros::valgrind::do_quick_leak_check();
                }
                let leak_count = ::macros::valgrind::count_leaks();
                assert!(leak_count.leaked == 0, "Valgrind reported leaked memory");
            }
        }
    )
);
<|endoftext|>


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

#[macro_export]
macro_rules! hsm_define_objects_noparents {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident),* ) ) => {
        hsm_define_objects!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
        hsm_state_parents!($st_en ; $($s -> None),*);
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident $x:tt),*)) => {
        hsm_define_objects!($st_str, $st_en, $st_evt, $shr_dat, ($($s $x),*) );
        hsm_state_parents!($st_en ; $($s -> None),*);
    }
}

#[macro_export]
macro_rules! hsm_define_objects {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident),* ) ) => {
        use $crate::Parent;
        _hsm_create_states!($($s),*);
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ( $($s:ident $x:tt),*)) => {
        use $crate::Parent;
        _hsm_create_states!( $($s $x),* );
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    }
}

#[macro_export]
macro_rules! hsm_delayed_transition {
    ($probe:ident, $x:block) => {
        match $probe {
            true  => $crate::Action::DelayedTransition,
            false => $crate::Action::Transition($x)
        }
    }
}

#[macro_export]
macro_rules! hsm_impl_state {
    ($state:ty, $events:ty, $states:ty, $shr_data:ty,
     $($pat:pat => $result:expr),*) => {
        impl<'a, 'b, 'c, 'd, 'e> $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, shr_data: &mut $shr_data, evt: &$crate::Event<$events>, probe: bool) -> $crate::Action<$states> {
                match *evt {
                    $( $pat => $result),*
                }
            }
        }
    };
    ($state:ty, $events:ty, $states:ty, $shr_data:ty,
     $shr:ident, $evt:ident, $probe:ident, $($pat:pat => $result:expr),*) => {
        impl<'a, 'b, 'c, 'd, 'e> $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, $shr: &mut $shr_data, $evt: &$crate::Event<$events>, $probe: bool) -> $crate::Action<$states> {
                match *$evt {
                    $( $pat => $result),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! hsm_state_parents {
    ($st_en:ident ; $($nam:ident -> $parent:ident),*) => {
        $(_hsm_impl_state_parent!($st_en ; $nam -> $parent);)*
    }
}

#[macro_export]
macro_rules! _hsm_impl_state_parent {
    ($st_en:ident ; $nam:ident -> None) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { None }
        }
    };
    ($st_en:ident ; $nam:ident -> $parent:ident) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { Some($st_en::$parent) }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_states {
    ( $($s:ident),* ) => {
        $(_hsm_create_state!($s);)*
    };
    ($($s:ident $x:tt),*) => {
        $(_hsm_create_state!($s $x);)*
    }
}

#[macro_export]
macro_rules! _hsm_create_state_common {
    ($nam:ident) => {
        impl $crate::Name for $nam {
            fn name(&self) -> &'static str {
                stringify!($nam)
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state {
    ($nam:ident) => {
        #[derive(Debug)]
        pub struct $nam;
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam
            }
        }
        _hsm_create_state_common!($nam);
    };
    ($nam:ident { $($field_name:ident : $field_type:ty = $field_default:expr),* }) => {
        #[derive(Debug)]
        pub struct $nam {
            _phantom        : ::std::marker::PhantomData<u8>,
            $( $field_name  : $field_type ),*
        }
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam {
                    _phantom        : ::std::marker::PhantomData,
                    $( $field_name  : $field_default ),*
                }
            }
        }
        _hsm_create_state_common!($nam);
    }
}

#[macro_export]
macro_rules! _hsm_create_state_enum {
    ($st_en:ident, ($($s:ident),*) ) => {
        #[derive(Debug, Clone, Eq, PartialEq)]
        pub enum $st_en {
            $( $s ),*
        }
        impl ::std::fmt::Display for $st_en {
            fn fmt(&self, f:&mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                match *self {
                    $( $st_en::$s => try!(::std::fmt::Display::fmt(stringify!($s), f)) ),*
                };
                Ok(())
            }
        }
        impl $crate::InstanceParent<$st_en> for $st_en {
            fn get_parent(&self) -> Option<$st_en> {
                match *self {
                    $( $st_en::$s => $s::get_parent() ),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state_struct {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ident, ($($s:ident),*) ) => {
        #[derive(Debug)]
        #[allow(non_snake_case)]
        pub struct $st_str {
            $( $s : $s ),*
        }
        impl $crate::Initializer for $st_str {
            fn new() -> Self {
                $st_str {
                    $( $s : $s::new() ),*
                }
            }
        }
        impl<'a, 'b, 'c, 'd, 'e> $crate::StateLookup<$st_en, $st_evt, $shr_dat> for $st_str {
            fn lookup(&mut self, typ: &$st_en) -> &mut $crate::State<$st_evt, $st_en, $shr_dat> {
                match *typ {
                    $($st_en::$s => &mut self.$s ),*
                }
            }
        }
    }
}
<commit_msg>change shared data to a ty in macros<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Mattis Marjak (mattis.marjak@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#[macro_export]
macro_rules! hsm_define_objects_noparents {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ty, ( $($s:ident),* ) ) => {
        hsm_define_objects!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
        hsm_state_parents!($st_en ; $($s -> None),*);
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ty, ( $($s:ident $x:tt),*)) => {
        hsm_define_objects!($st_str, $st_en, $st_evt, $shr_dat, ($($s $x),*) );
        hsm_state_parents!($st_en ; $($s -> None),*);
    }
}

#[macro_export]
macro_rules! hsm_define_objects {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ty, ( $($s:ident),* ) ) => {
        use $crate::Parent;
        _hsm_create_states!($($s),*);
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    };
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ty, ( $($s:ident $x:tt),*)) => {
        use $crate::Parent;
        _hsm_create_states!( $($s $x),* );
        _hsm_create_state_enum!($st_en, ($($s),*));
        _hsm_create_state_struct!($st_str, $st_en, $st_evt, $shr_dat, ($($s),*) );
    }
}

#[macro_export]
macro_rules! hsm_delayed_transition {
    ($probe:ident, $x:block) => {
        match $probe {
            true  => $crate::Action::DelayedTransition,
            false => $crate::Action::Transition($x)
        }
    }
}

#[macro_export]
macro_rules! hsm_impl_state {
    ($state:ty, $events:ty, $states:ty, $shr_data:ty,
     $($pat:pat => $result:expr),*) => {
        impl<'a, 'b, 'c, 'd, 'e> $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, shr_data: &mut $shr_data, evt: &$crate::Event<$events>, probe: bool) -> $crate::Action<$states> {
                match *evt {
                    $( $pat => $result),*
                }
            }
        }
    };
    ($state:ty, $events:ty, $states:ty, $shr_data:ty,
     $shr:ident, $evt:ident, $probe:ident, $($pat:pat => $result:expr),*) => {
        impl<'a, 'b, 'c, 'd, 'e> $crate::State<$events, $states, $shr_data> for $state {
            #[allow(unused_variables)]
            fn handle_event(&mut self, $shr: &mut $shr_data, $evt: &$crate::Event<$events>, $probe: bool) -> $crate::Action<$states> {
                match *$evt {
                    $( $pat => $result),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! hsm_state_parents {
    ($st_en:ident ; $($nam:ident -> $parent:ident),*) => {
        $(_hsm_impl_state_parent!($st_en ; $nam -> $parent);)*
    }
}

#[macro_export]
macro_rules! _hsm_impl_state_parent {
    ($st_en:ident ; $nam:ident -> None) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { None }
        }
    };
    ($st_en:ident ; $nam:ident -> $parent:ident) => {
        impl $crate::Parent<$st_en> for $nam {
            fn get_parent() -> Option<$st_en> { Some($st_en::$parent) }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_states {
    ( $($s:ident),* ) => {
        $(_hsm_create_state!($s);)*
    };
    ($($s:ident $x:tt),*) => {
        $(_hsm_create_state!($s $x);)*
    }
}

#[macro_export]
macro_rules! _hsm_create_state_common {
    ($nam:ident) => {
        impl $crate::Name for $nam {
            fn name(&self) -> &'static str {
                stringify!($nam)
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state {
    ($nam:ident) => {
        #[derive(Debug)]
        pub struct $nam;
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam
            }
        }
        _hsm_create_state_common!($nam);
    };
    ($nam:ident { $($field_name:ident : $field_type:ty = $field_default:expr),* }) => {
        #[derive(Debug)]
        pub struct $nam {
            _phantom        : ::std::marker::PhantomData<u8>,
            $( $field_name  : $field_type ),*
        }
        impl $crate::Initializer for $nam {
            fn new() -> Self {
                $nam {
                    _phantom        : ::std::marker::PhantomData,
                    $( $field_name  : $field_default ),*
                }
            }
        }
        _hsm_create_state_common!($nam);
    }
}

#[macro_export]
macro_rules! _hsm_create_state_enum {
    ($st_en:ident, ($($s:ident),*) ) => {
        #[derive(Debug, Clone, Eq, PartialEq)]
        pub enum $st_en {
            $( $s ),*
        }
        impl ::std::fmt::Display for $st_en {
            fn fmt(&self, f:&mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                match *self {
                    $( $st_en::$s => try!(::std::fmt::Display::fmt(stringify!($s), f)) ),*
                };
                Ok(())
            }
        }
        impl $crate::InstanceParent<$st_en> for $st_en {
            fn get_parent(&self) -> Option<$st_en> {
                match *self {
                    $( $st_en::$s => $s::get_parent() ),*
                }
            }
        }
    }
}

#[macro_export]
macro_rules! _hsm_create_state_struct {
    ($st_str:ident, $st_en:ident, $st_evt:ty, $shr_dat:ty, ($($s:ident),*) ) => {
        #[derive(Debug)]
        #[allow(non_snake_case)]
        pub struct $st_str {
            $( $s : $s ),*
        }
        impl $crate::Initializer for $st_str {
            fn new() -> Self {
                $st_str {
                    $( $s : $s::new() ),*
                }
            }
        }
        impl<'a, 'b, 'c, 'd, 'e> $crate::StateLookup<$st_en, $st_evt, $shr_dat> for $st_str {
            fn lookup(&mut self, typ: &$st_en) -> &mut $crate::State<$st_evt, $st_en, $shr_dat> {
                match *typ {
                    $($st_en::$s => &mut self.$s ),*
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/// A 2D Matrix type composed of `f64` elements.
///
/// The Matrix type supports simple arithmetic operations from the start and
/// provides convenient methods for accessing the elements of the matrix.
///
/// # Examples
/// ```
/// use numrs::matrix;
/// use numrs::matrix::Matrix;
///
/// // Create a new 2x2 matrix with all values 0.0
/// let m1 = Matrix::new(2, 2, 0.0);
///
/// // Creates a 2x2 matrix from the above vector in row major order
/// let elems = [1.0, 2.0, 3.0, 4.0];
/// let m2 = matrix::from_elems(2, 2, &elems);
///
/// let mut res = m1.clone() + m2.clone(); // add two matrices
/// res = m1.clone() - m2.clone(); // subtract 2 matrices
/// res = m1.clone() * m2.clone(); // matrix product of 2 matrices
/// res = m2.clone() * 5.0; // scalar product of a matrix
/// ```

extern crate num;

use self::num::traits::Num;
use std::ops::{Index, Add, Sub, Mul, Neg};

pub struct Matrix<T: Num + Clone + Copy> {
  rows: usize,
  cols: usize,
  data: Vec<T>
}

impl<T: Num + Clone + Copy> Index<usize> for Matrix<T> {
  type Output = [T];

  #[inline]
  fn index<'a>(&'a self, index: usize) -> &'a [T] {
    &self.data[self.rows * index..self.rows * index + self.cols]
  }
}

impl<T: Num + Clone + Copy> Clone for Matrix<T> {
  fn clone(&self) -> Matrix<T> {
    Matrix::<T> {
      rows: self.num_rows(),
      cols: self.num_cols(),
      data: self.data.clone()
    }
  }

  fn clone_from(&mut self, source: &Matrix<T>) {
    self.rows = source.num_rows();
    self.cols = source.num_cols();
    self.data = source.data.clone();
  }
}

impl<T: Num + Clone + Copy> Add<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn add(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_rows() == rhs.num_rows() && self.num_cols() == rhs.num_cols() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), self.num_cols(), T::zero());
      for i in 0..self.data.len() {
        new_mat.data[i] = self.data[i] + rhs.data[i];
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for addition.");
    }
  }
}

impl<T: Num + Clone + Copy> Sub<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn sub(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_rows() == rhs.num_rows() && self.num_cols() == rhs.num_cols() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), self.num_cols(), T::zero());
      for i in 0..self.data.len() {
        new_mat.data[i] = self.data[i] - rhs.data[i];
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for subtraction.");
    }
  }
}

impl<T: Num + Clone + Copy> Mul<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn mul(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_cols() == rhs.num_rows() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), rhs.num_cols(), T::zero());
      for i in 0..self.num_rows() {
        for j in 0..rhs.num_cols() {
          let mut sum: T = T::zero();
          for k in 0..self.num_cols() {
            sum = sum + self.get(i, k) * rhs.get(k, j);
          }
          new_mat.set(i, j, sum);
        }
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for multiplication.")
    }
  }
}

impl<T: Num + Clone + Copy + Neg<Output = T>> Neg for Matrix<T> {
  type Output = Matrix<T>;

  fn neg(self) -> Matrix<T> {
    let mut m = self.clone();
    for i in 0..self.data.len() {
      m.data[i] = -self.data[i];
    }
    m
  }
}

impl<T: Num + Clone + Copy> Mul<T> for Matrix<T> {
  type Output = Matrix<T>;

  fn mul(self, rhs: T) -> Matrix<T> {
    let mut m = self.clone();
    for i in 0..self.data.len() {
      m.data[i] = rhs * self.data[i];
    }
    m
  }
}

impl<T: Num + Clone + Copy> PartialEq for Matrix<T> {
  fn eq(&self, other: &Matrix<T>) -> bool {
    if self.num_rows() != other.num_rows() || self.num_cols() != other.num_cols() {
      return false;
    }
    for i in 0..self.data.len() {
      if self.data[i] != other.data[i] {
        return false;
      }
    }
    true
  }
}

impl<T: Num + Clone + Copy> Eq for Matrix<T> {}

impl<T: Num + Clone + Copy> Matrix<T> {
  /// Returns the number of rows in the matrix.
  #[inline]
  pub fn num_rows(&self) -> usize{
    self.rows
  }

  /// Returns the number of columns in the matrix.
  #[inline]
  pub fn num_cols(&self) -> usize {
    self.cols
  }

  /// Returns the element at `i`th row and `j`th column of the matrix.
  /// The row, column indexing is 0-based.
  #[inline]
  pub fn get(&self, i: usize, j: usize) -> T {
    if i < self.num_rows() && j < self.num_cols() {
      self.data[i * self.num_cols() + j]
    } else {
      panic!(format!("Matrix index ({}, {}) out of bounds.", i, j))
    }
  }

  /// Sets the element at `i`th row and `j`th column of the matrix as `num`.
  /// The row, column indexing is 0-based.
  #[inline]
  pub fn set(&mut self, i: usize, j: usize, num: T) {
    let (rows, cols) = (self.num_rows(), self.num_cols());
    if i < rows && j < cols {
      self.data[i * cols + j] = num
    } else {
      panic!(format!("Matrix index ({}, {}) out of bounds.", i, j))
    }
  }

  /// Creates a new `Matrix` with dimensions as `rows x cols` with all values
  /// instantiated to `default`.
  pub fn new(rows: usize, cols: usize, default: T) -> Matrix<T> {
    let mut d: Vec<T> = Vec::with_capacity(rows * cols);
    for i in 0..rows * cols {
      d.push(default);
    }
    Matrix::<T> {
      rows: rows,
      cols: cols,
      data: d
    }
  }

  /// Resizes the dimensions of the matrix with the new dimensions as
  /// `newrows x newcols`.
  pub fn reshape(&mut self, newrows: usize, newcols: usize) {
    if self.rows * self.cols == newrows * newcols {
      self.rows = newrows;
      self.cols = newcols;
    } else {
      panic!("Total number of elements in matrix should be same.")
    }
  }

  /// Returns the matrix as a cloned vector in row major order.
  pub fn get_vec(&self) -> Vec<T> {
    self.data.clone()
  }

  /// Transposes the matrix.
  pub fn transpose(&mut self) {
    let mut v = self.data.clone();
    for i in 0..self.num_rows() {
      for j in 0..self.num_cols() {
        v[j * self.num_cols() + i] = self.get(i, j);
      }
    }
    self.data = v;
  }

  /// Trace of the matrix.
  pub fn trace(&self) -> T {
    if self.num_rows() == self.num_cols() {
      let mut sum: T = T::zero();
      for i in 0..self.num_rows() {
        sum = sum + self.get(i, i);
      }
      return sum;
    }
    panic!("The matrix should be a square matrix.")
  }
}

/// Creates a `Matrix` with dimensions `rows x cols` from the elements of the
/// slice `elems`.
pub fn from_elems<T: Num + Clone + Copy>(rows: usize, cols: usize, elems: &[T]) -> Matrix<T> {
  let mut m = Matrix::<T> {
    rows: rows,
    cols: cols,
    data: Vec::new()
  };
  m.data.extend_from_slice(elems);
  m
}

/// Creates an identity matrix of dimension `n x n`.
pub fn identity<T: Num + Clone + Copy>(n: usize) -> Matrix<T> {
  let mut m = Matrix::<T>::new(n, n, T::zero());
  for i in 0..n {
    m.set(i, i, T::one());
  }
  m
}
<commit_msg>remove useless iterations<commit_after>/// A 2D Matrix type composed of `f64` elements.
///
/// The Matrix type supports simple arithmetic operations from the start and
/// provides convenient methods for accessing the elements of the matrix.
///
/// # Examples
/// ```
/// use numrs::matrix;
/// use numrs::matrix::Matrix;
///
/// // Create a new 2x2 matrix with all values 0.0
/// let m1 = Matrix::new(2, 2, 0.0);
///
/// // Creates a 2x2 matrix from the above vector in row major order
/// let elems = [1.0, 2.0, 3.0, 4.0];
/// let m2 = matrix::from_elems(2, 2, &elems);
///
/// let mut res = m1.clone() + m2.clone(); // add two matrices
/// res = m1.clone() - m2.clone(); // subtract 2 matrices
/// res = m1.clone() * m2.clone(); // matrix product of 2 matrices
/// res = m2.clone() * 5.0; // scalar product of a matrix
/// ```

extern crate num;

use self::num::traits::Num;
use std::ops::{Index, Add, Sub, Mul, Neg};

pub struct Matrix<T: Num + Clone + Copy> {
  rows: usize,
  cols: usize,
  data: Vec<T>
}

impl<T: Num + Clone + Copy> Index<usize> for Matrix<T> {
  type Output = [T];

  #[inline]
  fn index<'a>(&'a self, index: usize) -> &'a [T] {
    &self.data[self.rows * index..self.rows * index + self.cols]
  }
}

impl<T: Num + Clone + Copy> Clone for Matrix<T> {
  fn clone(&self) -> Matrix<T> {
    Matrix::<T> {
      rows: self.num_rows(),
      cols: self.num_cols(),
      data: self.data.clone()
    }
  }

  fn clone_from(&mut self, source: &Matrix<T>) {
    self.rows = source.num_rows();
    self.cols = source.num_cols();
    self.data = source.data.clone();
  }
}

impl<T: Num + Clone + Copy> Add<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn add(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_rows() == rhs.num_rows() && self.num_cols() == rhs.num_cols() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), self.num_cols(), T::zero());
      for i in 0..self.data.len() {
        new_mat.data[i] = self.data[i] + rhs.data[i];
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for addition.");
    }
  }
}

impl<T: Num + Clone + Copy> Sub<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn sub(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_rows() == rhs.num_rows() && self.num_cols() == rhs.num_cols() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), self.num_cols(), T::zero());
      for i in 0..self.data.len() {
        new_mat.data[i] = self.data[i] - rhs.data[i];
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for subtraction.");
    }
  }
}

impl<T: Num + Clone + Copy> Mul<Matrix<T>> for Matrix<T> {
  type Output = Matrix<T>;

  fn mul(self, rhs: Matrix<T>) -> Matrix<T> {
    if self.num_cols() == rhs.num_rows() {
      let mut new_mat = Matrix::<T>::new(self.num_rows(), rhs.num_cols(), T::zero());
      for i in 0..self.num_rows() {
        for j in 0..rhs.num_cols() {
          let mut sum: T = T::zero();
          for k in 0..self.num_cols() {
            sum = sum + self.get(i, k) * rhs.get(k, j);
          }
          new_mat.set(i, j, sum);
        }
      }
      new_mat
    } else {
      panic!("Matrices are not conformable for multiplication.")
    }
  }
}

impl<T: Num + Clone + Copy + Neg<Output = T>> Neg for Matrix<T> {
  type Output = Matrix<T>;

  fn neg(self) -> Matrix<T> {
    let mut m = self.clone();
    for i in 0..self.data.len() {
      m.data[i] = -self.data[i];
    }
    m
  }
}

impl<T: Num + Clone + Copy> Mul<T> for Matrix<T> {
  type Output = Matrix<T>;

  fn mul(self, rhs: T) -> Matrix<T> {
    let mut m = self.clone();
    for i in 0..self.data.len() {
      m.data[i] = rhs * self.data[i];
    }
    m
  }
}

impl<T: Num + Clone + Copy> PartialEq for Matrix<T> {
  fn eq(&self, other: &Matrix<T>) -> bool {
    if self.num_rows() != other.num_rows() || self.num_cols() != other.num_cols() {
      return false;
    }
    for i in 0..self.data.len() {
      if self.data[i] != other.data[i] {
        return false;
      }
    }
    true
  }
}

impl<T: Num + Clone + Copy> Eq for Matrix<T> {}

impl<T: Num + Clone + Copy> Matrix<T> {
  /// Returns the number of rows in the matrix.
  #[inline]
  pub fn num_rows(&self) -> usize{
    self.rows
  }

  /// Returns the number of columns in the matrix.
  #[inline]
  pub fn num_cols(&self) -> usize {
    self.cols
  }

  /// Returns the element at `i`th row and `j`th column of the matrix.
  /// The row, column indexing is 0-based.
  #[inline]
  pub fn get(&self, i: usize, j: usize) -> T {
    if i < self.num_rows() && j < self.num_cols() {
      self.data[i * self.num_cols() + j]
    } else {
      panic!(format!("Matrix index ({}, {}) out of bounds.", i, j))
    }
  }

  /// Sets the element at `i`th row and `j`th column of the matrix as `num`.
  /// The row, column indexing is 0-based.
  #[inline]
  pub fn set(&mut self, i: usize, j: usize, num: T) {
    let (rows, cols) = (self.num_rows(), self.num_cols());
    if i < rows && j < cols {
      self.data[i * cols + j] = num
    } else {
      panic!(format!("Matrix index ({}, {}) out of bounds.", i, j))
    }
  }

  /// Creates a new `Matrix` with dimensions as `rows x cols` with all values
  /// instantiated to `default`.
  pub fn new(rows: usize, cols: usize, default: T) -> Matrix<T> {
    let d = vec![default; rows * cols];
    Matrix::<T> {
      rows: rows,
      cols: cols,
      data: d
    }
  }

  /// Resizes the dimensions of the matrix with the new dimensions as
  /// `newrows x newcols`.
  pub fn reshape(&mut self, newrows: usize, newcols: usize) {
    if self.rows * self.cols == newrows * newcols {
      self.rows = newrows;
      self.cols = newcols;
    } else {
      panic!("Total number of elements in matrix should be same.")
    }
  }

  /// Returns the matrix as a cloned vector in row major order.
  pub fn get_vec(&self) -> Vec<T> {
    self.data.clone()
  }

  /// Transposes the matrix.
  pub fn transpose(&mut self) {
    let mut v = self.data.clone();
    for i in 0..self.num_rows() {
      for j in 0..self.num_cols() {
        v[j * self.num_cols() + i] = self.get(i, j);
      }
    }
    self.data = v;
  }

  /// Trace of the matrix.
  pub fn trace(&self) -> T {
    if self.num_rows() == self.num_cols() {
      let mut sum: T = T::zero();
      for i in 0..self.num_rows() {
        sum = sum + self.get(i, i);
      }
      return sum;
    }
    panic!("The matrix should be a square matrix.")
  }
}

/// Creates a `Matrix` with dimensions `rows x cols` from the elements of the
/// slice `elems`.
pub fn from_elems<T: Num + Clone + Copy>(rows: usize, cols: usize, elems: &[T]) -> Matrix<T> {
  let mut m = Matrix::<T> {
    rows: rows,
    cols: cols,
    data: Vec::with_capacity(rows * cols)
  };
  m.data.extend_from_slice(elems);
  m
}

/// Creates an identity matrix of dimension `n x n`.
pub fn identity<T: Num + Clone + Copy>(n: usize) -> Matrix<T> {
  let mut m = Matrix::<T>::new(n, n, T::zero());
  for i in 0..n {
    m.set(i, i, T::one());
  }
  m
}
<|endoftext|>