<commit_before>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! use futures::{Future, Stream};
//! use tokio_postgres::NoTls;
//!
//! # #[cfg(not(feature = "runtime"))]
//! # let fut = futures::future::ok(());
//! # #[cfg(feature = "runtime")]
//! let fut =
//!     // Connect to the database
//!     tokio_postgres::connect("host=localhost user=postgres", NoTls)
//!
//!     .map(|(client, connection)| {
//!         // The connection object performs the actual communication with the database,
//!         // so spawn it off to run on its own.
//!         let connection = connection.map_err(|e| eprintln!("connection error: {}", e));
//!         tokio::spawn(connection);
//!
//!         // The client is what you use to make requests.
//!         client
//!     })
//!
//!     .and_then(|mut client| {
//!         // Now we can prepare a simple statement that just returns its parameter.
//!         client.prepare("SELECT $1::TEXT")
//!             .map(|statement| (client, statement))
//!     })
//!
//!     .and_then(|(mut client, statement)| {
//!         // And then execute it, returning a Stream of Rows which we collect into a Vec
//!         client.query(&statement, &[&"hello world"]).collect()
//!     })
//!
//!     // Now we can check that we got back the same string we sent over.
//!     .map(|rows| {
//!         let value: &str = rows[0].get(0);
//!         assert_eq!(value, "hello world");
//!     })
//!
//!     // And report any errors that happened.
//!     .map_err(|e| {
//!         eprintln!("error: {}", e);
//!     });
//!
//! // By default, tokio_postgres uses the tokio crate as its runtime.
//! tokio::run(fut);
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! fn pipelined_prepare(
//!     client: &mut Client,
//! ) -> impl Future<Item = (Statement, Statement), Error = Error>
//! {
//!     client.prepare("SELECT * FROM foo")
//!         .join(client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)"))
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.4.0-rc.3")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]
#![feature(async_await)]

pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::row::{Row, SimpleQueryRow};
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use statement::{Column, Statement};

mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
pub mod error;
mod maybe_tls_stream;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: ./Config.t.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    config.connect(tls).await
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
    #[doc(hidden)]
    __NonExhaustive,
}

/// Message returned by the `SimpleQuery` stream.
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
    #[doc(hidden)]
    __NonExhaustive,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}
<commit_msg>Fix doc examples<commit_after>//! An asynchronous, pipelined, PostgreSQL client.
//!
//! # Example
//!
//! ```no_run
//! #![feature(async_await)]
//!
//! use futures::{FutureExt, TryStreamExt};
//! use tokio_postgres::{NoTls, Error, Row};
//!
//! # #[cfg(feature = "runtime")]
//! #[tokio::main]
//! async fn main() -> Result<(), Error> {
//!     // Connect to the database.
//!     let (mut client, connection) = tokio_postgres::connect("host=localhost user=postgres", NoTls).await?;
//!
//!     // The connection object performs the actual communication with the database,
//!     // so spawn it off to run on its own.
//!     let connection = connection.map(|r| {
//!         if let Err(e) = r {
//!             eprintln!("connection error: {}", e);
//!         }
//!     });
//!     tokio::spawn(connection);
//!
//!     // Now we can prepare a simple statement that just returns its parameter.
//!     let stmt = client.prepare("SELECT $1::TEXT").await?;
//!
//!     // And then execute it, returning a Stream of Rows which we collect into a Vec.
//!     let rows: Vec<Row> = client
//!         .query(&stmt, &[&"hello world"])
//!         .try_collect()
//!         .await?;
//!
//!     // Now we can check that we got back the same string we sent over.
//!     let value: &str = rows[0].get(0);
//!     assert_eq!(value, "hello world");
//!
//!     Ok(())
//! }
//! ```
//!
//! # Behavior
//!
//! Calling a method like `Client::query` on its own does nothing. The associated request is not sent to the database
//! until the future returned by the method is first polled. Requests are executed in the order that they are first
//! polled, not in the order that their futures are created.
//!
//! # Pipelining
//!
//! The client supports *pipelined* requests. Pipelining can improve performance in use cases in which multiple,
//! independent queries need to be executed. In a traditional workflow, each query is sent to the server after the
//! previous query completes. In contrast, pipelining allows the client to send all of the queries to the server up
//! front, minimizing time spent by one side waiting for the other to finish sending data:
//!
//! ```not_rust
//!             Sequential                              Pipelined
//! | Client         | Server          |    | Client         | Server          |
//! |----------------|-----------------|    |----------------|-----------------|
//! | send query 1   |                 |    | send query 1   |                 |
//! |                | process query 1 |    | send query 2   | process query 1 |
//! | receive rows 1 |                 |    | send query 3   | process query 2 |
//! | send query 2   |                 |    | receive rows 1 | process query 3 |
//! |                | process query 2 |    | receive rows 2 |                 |
//! | receive rows 2 |                 |    | receive rows 3 |                 |
//! | send query 3   |                 |
//! |                | process query 3 |
//! | receive rows 3 |                 |
//! ```
//!
//! In both cases, the PostgreSQL server is executing the queries sequentially - pipelining just allows both sides of
//! the connection to work concurrently when possible.
//!
//! Pipelining happens automatically when futures are polled concurrently (for example, by using the futures `join`
//! combinator):
//!
//! ```rust
//! use futures::future;
//! use std::future::Future;
//! use tokio_postgres::{Client, Error, Statement};
//!
//! fn pipelined_prepare(
//!     client: &mut Client,
//! ) -> impl Future<Output = Result<(Statement, Statement), Error>>
//! {
//!     future::try_join(
//!         client.prepare("SELECT * FROM foo"),
//!         client.prepare("INSERT INTO bar (id, name) VALUES ($1, $2)")
//!     )
//! }
//! ```
//!
//! # Runtime
//!
//! The client works with arbitrary `AsyncRead + AsyncWrite` streams. Convenience APIs are provided to handle the
//! connection process, but these are gated by the `runtime` Cargo feature, which is enabled by default. If disabled,
//! all dependence on the tokio runtime is removed.
//!
//! # SSL/TLS support
//!
//! TLS support is implemented via external libraries. `Client::connect` and `Config::connect` take a TLS implementation
//! as an argument. The `NoTls` type in this crate can be used when TLS is not required. Otherwise, the
//! `postgres-openssl` and `postgres-native-tls` crates provide implementations backed by the `openssl` and `native-tls`
//! crates, respectively.
#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.4.0-rc.3")]
#![warn(rust_2018_idioms, clippy::all, missing_docs)]
#![feature(async_await)]

pub use crate::client::Client;
pub use crate::config::Config;
pub use crate::connection::Connection;
use crate::error::DbError;
pub use crate::error::Error;
pub use crate::row::{Row, SimpleQueryRow};
#[cfg(feature = "runtime")]
pub use crate::socket::Socket;
#[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls;
pub use statement::{Column, Statement};

mod client;
mod codec;
pub mod config;
#[cfg(feature = "runtime")]
mod connect;
mod connect_raw;
#[cfg(feature = "runtime")]
mod connect_socket;
mod connect_tls;
mod connection;
pub mod error;
mod maybe_tls_stream;
mod prepare;
mod query;
pub mod row;
mod simple_query;
#[cfg(feature = "runtime")]
mod socket;
mod statement;
pub mod tls;
pub mod types;

/// A convenience function which parses a connection string and connects to the database.
///
/// See the documentation for [`Config`] for details on the connection string format.
///
/// Requires the `runtime` Cargo feature (enabled by default).
///
/// [`Config`]: ./Config.t.html
#[cfg(feature = "runtime")]
pub async fn connect<T>(
    config: &str,
    tls: T,
) -> Result<(Client, Connection<Socket, T::Stream>), Error>
where
    T: MakeTlsConnect<Socket>,
{
    let config = config.parse::<Config>()?;
    config.connect(tls).await
}

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    process_id: i32,
    channel: String,
    payload: String,
}

/// An asynchronous message from the server.
#[allow(clippy::large_enum_variant)]
pub enum AsyncMessage {
    /// A notice.
    ///
    /// Notices use the same format as errors, but aren't "errors" per-se.
    Notice(DbError),
    /// A notification.
    ///
    /// Connections can subscribe to notifications with the `LISTEN` command.
    Notification(Notification),
    #[doc(hidden)]
    __NonExhaustive,
}

/// Message returned by the `SimpleQuery` stream.
pub enum SimpleQueryMessage {
    /// A row of data.
    Row(SimpleQueryRow),
    /// A statement in the query has completed.
    ///
    /// The number of rows modified or selected is returned.
    CommandComplete(u64),
    #[doc(hidden)]
    __NonExhaustive,
}

impl Notification {
    /// The process ID of the notifying backend process.
    pub fn process_id(&self) -> i32 {
        self.process_id
    }

    /// The name of the channel that the notify has been raised on.
    pub fn channel(&self) -> &str {
        &self.channel
    }

    /// The "payload" string passed from the notifying process.
    pub fn payload(&self) -> &str {
        &self.payload
    }
}
<|endoftext|>


<commit_before>//! Allows a future to execute for a maximum amount of time.
//!
//! See [`Timeout`] documentation for more details.
//!
//! [`Timeout`]: struct@Timeout

use crate::{
    coop,
    time::{error::Elapsed, sleep_until, Duration, Instant, Sleep},
    util::trace,
};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Requires a `Future` to complete before the specified duration has elapsed.
///
/// If the future completes before the duration has elapsed, then the completed
/// value is returned. Otherwise, an error is returned and the future is
/// canceled.
///
/// This function returns a future whose return type is [`Result`]`<T,`[`Elapsed`]`>`, where `T` is the
/// return type of the provided future.
///
/// [`Result`]: std::result::Result
/// [`Elapsed`]: crate::time::error::Elapsed
///
/// # Cancellation
///
/// Cancelling a timeout is done by dropping the future. No additional cleanup
/// or other work is required.
///
/// The original future may be obtained by calling [`Timeout::into_inner`]. This
/// consumes the `Timeout`.
///
/// # Examples
///
/// Create a new `Timeout` set to expire in 10 milliseconds.
///
/// ```rust
/// use tokio::time::timeout;
/// use tokio::sync::oneshot;
///
/// use std::time::Duration;
///
/// # async fn dox() {
/// let (tx, rx) = oneshot::channel();
/// # tx.send(()).unwrap();
///
/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.
/// if let Err(_) = timeout(Duration::from_millis(10), rx).await {
///     println!("did not receive value within 10 ms");
/// }
/// # }
/// ```
///
/// # Panics
///
/// This function panics if there is no current timer set.
///
/// It can be triggered when [`Builder::enable_time`] or
/// [`Builder::enable_all`] are not included in the builder.
///
/// It can also panic whenever a timer is created outside of a
/// Tokio runtime. That is why `rt.block_on(sleep(...))` will panic,
/// since the function is executed outside of the runtime.
/// Whereas `rt.block_on(async {sleep(...).await})` doesn't panic.
/// And this is because wrapping the function on an async makes it lazy,
/// and so gets executed inside the runtime successfully without
/// panicking.
///
/// [`Builder::enable_time`]: crate::runtime::Builder::enable_time
/// [`Builder::enable_all`]: crate::runtime::Builder::enable_all
#[track_caller]
pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F>
where
    F: Future,
{
    let location = trace::caller_location();

    let deadline = Instant::now().checked_add(duration);
    let delay = match deadline {
        Some(deadline) => Sleep::new_timeout(deadline, location),
        None => Sleep::far_future(location),
    };
    Timeout::new_with_delay(future, delay)
}

/// Requires a `Future` to complete before the specified instant in time.
///
/// If the future completes before the instant is reached, then the completed
/// value is returned. Otherwise, an error is returned.
///
/// This function returns a future whose return type is [`Result`]`<T,`[`Elapsed`]`>`, where `T` is the
/// return type of the provided future.
///
/// [`Result`]: std::result::Result
/// [`Elapsed`]: crate::time::error::Elapsed
///
/// # Cancellation
///
/// Cancelling a timeout is done by dropping the future. No additional cleanup
/// or other work is required.
///
/// The original future may be obtained by calling [`Timeout::into_inner`]. This
/// consumes the `Timeout`.
///
/// # Examples
///
/// Create a new `Timeout` set to expire in 10 milliseconds.
///
/// ```rust
/// use tokio::time::{Instant, timeout_at};
/// use tokio::sync::oneshot;
///
/// use std::time::Duration;
///
/// # async fn dox() {
/// let (tx, rx) = oneshot::channel();
/// # tx.send(()).unwrap();
///
/// // Wrap the future with a `Timeout` set to expire 10 milliseconds into the
/// // future.
/// if let Err(_) = timeout_at(Instant::now() + Duration::from_millis(10), rx).await {
///     println!("did not receive value within 10 ms");
/// }
/// # }
/// ```
pub fn timeout_at<F>(deadline: Instant, future: F) -> Timeout<F>
where
    F: Future,
{
    let delay = sleep_until(deadline);

    Timeout {
        value: future,
        delay,
    }
}

pin_project! {
    /// Future returned by [`timeout`](timeout) and [`timeout_at`](timeout_at).
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    #[derive(Debug)]
    pub struct Timeout<T> {
        #[pin]
        value: T,
        #[pin]
        delay: Sleep,
    }
}

impl<T> Timeout<T> {
    pub(crate) fn new_with_delay(value: T, delay: Sleep) -> Timeout<T> {
        Timeout { value, delay }
    }

    /// Gets a reference to the underlying value in this timeout.
    pub fn get_ref(&self) -> &T {
        &self.value
    }

    /// Gets a mutable reference to the underlying value in this timeout.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.value
    }

    /// Consumes this timeout, returning the underlying value.
    pub fn into_inner(self) -> T {
        self.value
    }
}

impl<T> Future for Timeout<T>
where
    T: Future,
{
    type Output = Result<T::Output, Elapsed>;

    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        let me = self.project();

        let had_budget_before = coop::has_budget_remaining();

        // First, try polling the future
        if let Poll::Ready(v) = me.value.poll(cx) {
            return Poll::Ready(Ok(v));
        }

        let has_budget_now = coop::has_budget_remaining();

        let delay = me.delay;

        let poll_delay = || -> Poll<Self::Output> {
            match delay.poll(cx) {
                Poll::Ready(()) => Poll::Ready(Err(Elapsed::new())),
                Poll::Pending => Poll::Pending,
            }
        };

        if let (true, false) = (had_budget_before, has_budget_now) {
            // if it is the underlying future that exhausted the budget, we poll
            // the `delay` with an unconstrained one. This prevents pathological
            // cases where the underlying future always exhausts the budget and
            // we never get a chance to evaluate whether the timeout was hit or
            // not.
            coop::with_unconstrained(poll_delay)
        } else {
            poll_delay()
        }
    }
}
<commit_msg>time: document that timeouts check only before poll (#5126)<commit_after>//! Allows a future to execute for a maximum amount of time.
//!
//! See [`Timeout`] documentation for more details.
//!
//! [`Timeout`]: struct@Timeout

use crate::{
    coop,
    time::{error::Elapsed, sleep_until, Duration, Instant, Sleep},
    util::trace,
};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Requires a `Future` to complete before the specified duration has elapsed.
///
/// If the future completes before the duration has elapsed, then the completed
/// value is returned. Otherwise, an error is returned and the future is
/// canceled.
///
/// Note that the timeout is checked before polling the future, so if the future
/// does not yield during execution then it is possible for the future to complete
/// and exceed the timeout _without_ returning an error.
///
/// This function returns a future whose return type is [`Result`]`<T,`[`Elapsed`]`>`, where `T` is the
/// return type of the provided future.
///
/// [`Result`]: std::result::Result
/// [`Elapsed`]: crate::time::error::Elapsed
///
/// # Cancellation
///
/// Cancelling a timeout is done by dropping the future. No additional cleanup
/// or other work is required.
///
/// The original future may be obtained by calling [`Timeout::into_inner`]. This
/// consumes the `Timeout`.
///
/// # Examples
///
/// Create a new `Timeout` set to expire in 10 milliseconds.
///
/// ```rust
/// use tokio::time::timeout;
/// use tokio::sync::oneshot;
///
/// use std::time::Duration;
///
/// # async fn dox() {
/// let (tx, rx) = oneshot::channel();
/// # tx.send(()).unwrap();
///
/// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.
/// if let Err(_) = timeout(Duration::from_millis(10), rx).await {
///     println!("did not receive value within 10 ms");
/// }
/// # }
/// ```
///
/// # Panics
///
/// This function panics if there is no current timer set.
///
/// It can be triggered when [`Builder::enable_time`] or
/// [`Builder::enable_all`] are not included in the builder.
///
/// It can also panic whenever a timer is created outside of a
/// Tokio runtime. That is why `rt.block_on(sleep(...))` will panic,
/// since the function is executed outside of the runtime.
/// Whereas `rt.block_on(async {sleep(...).await})` doesn't panic.
/// And this is because wrapping the function on an async makes it lazy,
/// and so gets executed inside the runtime successfully without
/// panicking.
///
/// [`Builder::enable_time`]: crate::runtime::Builder::enable_time
/// [`Builder::enable_all`]: crate::runtime::Builder::enable_all
#[track_caller]
pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F>
where
    F: Future,
{
    let location = trace::caller_location();

    let deadline = Instant::now().checked_add(duration);
    let delay = match deadline {
        Some(deadline) => Sleep::new_timeout(deadline, location),
        None => Sleep::far_future(location),
    };
    Timeout::new_with_delay(future, delay)
}

/// Requires a `Future` to complete before the specified instant in time.
///
/// If the future completes before the instant is reached, then the completed
/// value is returned. Otherwise, an error is returned.
///
/// This function returns a future whose return type is [`Result`]`<T,`[`Elapsed`]`>`, where `T` is the
/// return type of the provided future.
///
/// [`Result`]: std::result::Result
/// [`Elapsed`]: crate::time::error::Elapsed
///
/// # Cancellation
///
/// Cancelling a timeout is done by dropping the future. No additional cleanup
/// or other work is required.
///
/// The original future may be obtained by calling [`Timeout::into_inner`]. This
/// consumes the `Timeout`.
///
/// # Examples
///
/// Create a new `Timeout` set to expire in 10 milliseconds.
///
/// ```rust
/// use tokio::time::{Instant, timeout_at};
/// use tokio::sync::oneshot;
///
/// use std::time::Duration;
///
/// # async fn dox() {
/// let (tx, rx) = oneshot::channel();
/// # tx.send(()).unwrap();
///
/// // Wrap the future with a `Timeout` set to expire 10 milliseconds into the
/// // future.
/// if let Err(_) = timeout_at(Instant::now() + Duration::from_millis(10), rx).await {
///     println!("did not receive value within 10 ms");
/// }
/// # }
/// ```
pub fn timeout_at<F>(deadline: Instant, future: F) -> Timeout<F>
where
    F: Future,
{
    let delay = sleep_until(deadline);

    Timeout {
        value: future,
        delay,
    }
}

pin_project! {
    /// Future returned by [`timeout`](timeout) and [`timeout_at`](timeout_at).
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    #[derive(Debug)]
    pub struct Timeout<T> {
        #[pin]
        value: T,
        #[pin]
        delay: Sleep,
    }
}

impl<T> Timeout<T> {
    pub(crate) fn new_with_delay(value: T, delay: Sleep) -> Timeout<T> {
        Timeout { value, delay }
    }

    /// Gets a reference to the underlying value in this timeout.
    pub fn get_ref(&self) -> &T {
        &self.value
    }

    /// Gets a mutable reference to the underlying value in this timeout.
    pub fn get_mut(&mut self) -> &mut T {
        &mut self.value
    }

    /// Consumes this timeout, returning the underlying value.
    pub fn into_inner(self) -> T {
        self.value
    }
}

impl<T> Future for Timeout<T>
where
    T: Future,
{
    type Output = Result<T::Output, Elapsed>;

    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        let me = self.project();

        let had_budget_before = coop::has_budget_remaining();

        // First, try polling the future
        if let Poll::Ready(v) = me.value.poll(cx) {
            return Poll::Ready(Ok(v));
        }

        let has_budget_now = coop::has_budget_remaining();

        let delay = me.delay;

        let poll_delay = || -> Poll<Self::Output> {
            match delay.poll(cx) {
                Poll::Ready(()) => Poll::Ready(Err(Elapsed::new())),
                Poll::Pending => Poll::Pending,
            }
        };

        if let (true, false) = (had_budget_before, has_budget_now) {
            // if it is the underlying future that exhausted the budget, we poll
            // the `delay` with an unconstrained one. This prevents pathological
            // cases where the underlying future always exhausts the budget and
            // we never get a chance to evaluate whether the timeout was hit or
            // not.
            coop::with_unconstrained(poll_delay)
        } else {
            poll_delay()
        }
    }
}
<|endoftext|>


<commit_before>use super::protocol::*;
use std::io::Read;
use xml::attribute::OwnedAttribute;
use xml::reader::ParserConfig;
use xml::reader::XmlEvent;
use xml::EventReader;

macro_rules! extract_from(
    ($it: expr => $pattern: pat => $result: expr) => (
        match $it.next() {
            Ok($pattern) => { $result },
            e => panic!("Ill-formed protocol file: {:?}", e)
        }
    )
);

macro_rules! extract_end_tag(
    ($it: expr => $tag: expr) => (
        extract_from!($it => XmlEvent::EndElement { name } => {
            assert!(name.local_name == $tag, "Ill-formed protocol file");
        });
    )
);

pub fn parse<S: Read>(stream: S) -> Protocol {
    let mut reader =
        EventReader::new_with_config(stream, ParserConfig::new().trim_whitespace(true));
    reader.next().expect("Could not read from event reader");
    parse_protocol(reader)
}

fn parse_protocol<R: Read>(mut reader: EventReader<R>) -> Protocol {
    let mut protocol = extract_from!(
        reader => XmlEvent::StartElement { name, attributes, .. } => {
            assert!(name.local_name == "protocol", "Missing protocol toplevel tag");
            assert!(attributes[0].name.local_name == "name", "Protocol must have a name");
            Protocol::new(attributes[0].value.clone())
        }
    );

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match &name.local_name[..] {
                    "copyright" => {
                        // parse the copyright
                        let copyright = match reader.next() {
                            Ok(XmlEvent::Characters(copyright))
                            | Ok(XmlEvent::CData(copyright)) => copyright,
                            e => panic!("Ill-formed protocol file: {:?}", e),
                        };

                        extract_end_tag!(reader => "copyright");
                        protocol.copyright = Some(copyright);
                    }
                    "interface" => {
                        protocol.interfaces.push(parse_interface(&mut reader, attributes));
                    }
                    "description" => {
                        protocol.description = Some(parse_description(&mut reader, attributes));
                    }
                    _ => panic!(
                        "Ill-formed protocol file: unexpected token `{}` in protocol {}",
                        name.local_name, protocol.name
                    ),
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                assert!(
                    name.local_name == "protocol",
                    "Unexpected closing token `{}`",
                    name.local_name
                );
                break;
            }
            e => panic!("Ill-formed protocol file: {:?}", e),
        }
    }

    protocol
}

fn parse_interface<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Interface {
    let mut interface = Interface::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => interface.name = attr.value,
            "version" => interface.version = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => {
                    interface.description = Some(parse_description(reader, attributes))
                }
                "request" => interface.requests.push(parse_request(reader, attributes)),
                "event" => interface.events.push(parse_event(reader, attributes)),
                "enum" => interface.enums.push(parse_enum(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "interface" => break,
            _ => {}
        }
    }

    interface
}

fn parse_description<R: Read>(
    reader: &mut EventReader<R>,
    attrs: Vec<OwnedAttribute>,
) -> (String, String) {
    let mut summary = String::new();
    for attr in attrs {
        if &attr.name.local_name[..] == "summary" {
            summary = attr.value.split_whitespace().collect::<Vec<_>>().join(" ");
        }
    }

    let description = match reader.next() {
        Ok(XmlEvent::Characters(txt)) => {
            extract_end_tag!(reader => "description");
            txt
        }
        Ok(XmlEvent::EndElement { ref name }) if name.local_name == "description" => String::new(),
        e => panic!("Ill-formed protocol file: {:?}", e),
    };

    (summary, description)
}

fn parse_request<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut request = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => request.name = attr.value,
            "type" => request.typ = Some(parse_type(&attr.value)),
            "since" => request.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => request.description = Some(parse_description(reader, attributes)),
                "arg" => request.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "request" => break,
            _ => {}
        }
    }

    request
}

fn parse_enum<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Enum {
    let mut enu = Enum::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => enu.name = attr.value,
            "since" => enu.since = attr.value.parse().unwrap(),
            "bitfield" => {
                if &attr.value[..] == "true" {
                    enu.bitfield = true
                }
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => enu.description = Some(parse_description(reader, attributes)),
                "entry" => enu.entries.push(parse_entry(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "enum" => break,
            _ => {}
        }
    }

    enu
}

fn parse_event<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut event = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => event.name = attr.value,
            "type" => event.typ = Some(parse_type(&attr.value)),
            "since" => event.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => event.description = Some(parse_description(reader, attributes)),
                "arg" => event.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "event" => break,
            _ => {}
        }
    }

    event
}

fn parse_arg<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Arg {
    let mut arg = Arg::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => arg.name = attr.value,
            "type" => arg.typ = parse_type(&attr.value),
            "summary" => {
                arg.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            "interface" => arg.interface = Some(attr.value),
            "allow-null" => {
                if attr.value == "true" {
                    arg.allow_null = true
                }
            }
            "enum" => arg.enum_ = Some(attr.value),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => arg.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "arg" => break,
            _ => {}
        }
    }

    arg
}

fn parse_type(txt: &str) -> Type {
    match txt {
        "int" => Type::Int,
        "uint" => Type::Uint,
        "fixed" => Type::Fixed,
        "string" => Type::String,
        "object" => Type::Object,
        "new_id" => Type::NewId,
        "array" => Type::Array,
        "fd" => Type::Fd,
        "destructor" => Type::Destructor,
        e => panic!("Unexpected type: {}", e),
    }
}

fn parse_entry<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Entry {
    let mut entry = Entry::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => entry.name = attr.value,
            "value" => {
                entry.value = if attr.value.starts_with("0x") {
                    u32::from_str_radix(&attr.value[2..], 16).unwrap()
                } else {
                    attr.value.parse().unwrap()
                };
            }
            "since" => entry.since = attr.value.parse().unwrap(),
            "summary" => {
                entry.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => entry.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "entry" => break,
            _ => {}
        }
    }

    entry
}
<commit_msg>Replace 'tocken' with 'token' in scanner<commit_after>use super::protocol::*;
use std::io::Read;
use xml::attribute::OwnedAttribute;
use xml::reader::ParserConfig;
use xml::reader::XmlEvent;
use xml::EventReader;

macro_rules! extract_from(
    ($it: expr => $pattern: pat => $result: expr) => (
        match $it.next() {
            Ok($pattern) => { $result },
            e => panic!("Ill-formed protocol file: {:?}", e)
        }
    )
);

macro_rules! extract_end_tag(
    ($it: expr => $tag: expr) => (
        extract_from!($it => XmlEvent::EndElement { name } => {
            assert!(name.local_name == $tag, "Ill-formed protocol file");
        });
    )
);

pub fn parse<S: Read>(stream: S) -> Protocol {
    let mut reader =
        EventReader::new_with_config(stream, ParserConfig::new().trim_whitespace(true));
    reader.next().expect("Could not read from event reader");
    parse_protocol(reader)
}

fn parse_protocol<R: Read>(mut reader: EventReader<R>) -> Protocol {
    let mut protocol = extract_from!(
        reader => XmlEvent::StartElement { name, attributes, .. } => {
            assert!(name.local_name == "protocol", "Missing protocol toplevel tag");
            assert!(attributes[0].name.local_name == "name", "Protocol must have a name");
            Protocol::new(attributes[0].value.clone())
        }
    );

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match &name.local_name[..] {
                    "copyright" => {
                        // parse the copyright
                        let copyright = match reader.next() {
                            Ok(XmlEvent::Characters(copyright))
                            | Ok(XmlEvent::CData(copyright)) => copyright,
                            e => panic!("Ill-formed protocol file: {:?}", e),
                        };

                        extract_end_tag!(reader => "copyright");
                        protocol.copyright = Some(copyright);
                    }
                    "interface" => {
                        protocol.interfaces.push(parse_interface(&mut reader, attributes));
                    }
                    "description" => {
                        protocol.description = Some(parse_description(&mut reader, attributes));
                    }
                    _ => panic!(
                        "Ill-formed protocol file: unexpected token `{}` in protocol {}",
                        name.local_name, protocol.name
                    ),
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                assert!(
                    name.local_name == "protocol",
                    "Unexpected closing token `{}`",
                    name.local_name
                );
                break;
            }
            e => panic!("Ill-formed protocol file: {:?}", e),
        }
    }

    protocol
}

fn parse_interface<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Interface {
    let mut interface = Interface::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => interface.name = attr.value,
            "version" => interface.version = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => {
                    interface.description = Some(parse_description(reader, attributes))
                }
                "request" => interface.requests.push(parse_request(reader, attributes)),
                "event" => interface.events.push(parse_event(reader, attributes)),
                "enum" => interface.enums.push(parse_enum(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "interface" => break,
            _ => {}
        }
    }

    interface
}

fn parse_description<R: Read>(
    reader: &mut EventReader<R>,
    attrs: Vec<OwnedAttribute>,
) -> (String, String) {
    let mut summary = String::new();
    for attr in attrs {
        if &attr.name.local_name[..] == "summary" {
            summary = attr.value.split_whitespace().collect::<Vec<_>>().join(" ");
        }
    }

    let description = match reader.next() {
        Ok(XmlEvent::Characters(txt)) => {
            extract_end_tag!(reader => "description");
            txt
        }
        Ok(XmlEvent::EndElement { ref name }) if name.local_name == "description" => String::new(),
        e => panic!("Ill-formed protocol file: {:?}", e),
    };

    (summary, description)
}

fn parse_request<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut request = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => request.name = attr.value,
            "type" => request.typ = Some(parse_type(&attr.value)),
            "since" => request.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => request.description = Some(parse_description(reader, attributes)),
                "arg" => request.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "request" => break,
            _ => {}
        }
    }

    request
}

fn parse_enum<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Enum {
    let mut enu = Enum::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => enu.name = attr.value,
            "since" => enu.since = attr.value.parse().unwrap(),
            "bitfield" => {
                if &attr.value[..] == "true" {
                    enu.bitfield = true
                }
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => enu.description = Some(parse_description(reader, attributes)),
                "entry" => enu.entries.push(parse_entry(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "enum" => break,
            _ => {}
        }
    }

    enu
}

fn parse_event<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut event = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => event.name = attr.value,
            "type" => event.typ = Some(parse_type(&attr.value)),
            "since" => event.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => event.description = Some(parse_description(reader, attributes)),
                "arg" => event.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "event" => break,
            _ => {}
        }
    }

    event
}

fn parse_arg<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Arg {
    let mut arg = Arg::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => arg.name = attr.value,
            "type" => arg.typ = parse_type(&attr.value),
            "summary" => {
                arg.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            "interface" => arg.interface = Some(attr.value),
            "allow-null" => {
                if attr.value == "true" {
                    arg.allow_null = true
                }
            }
            "enum" => arg.enum_ = Some(attr.value),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => arg.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "arg" => break,
            _ => {}
        }
    }

    arg
}

fn parse_type(txt: &str) -> Type {
    match txt {
        "int" => Type::Int,
        "uint" => Type::Uint,
        "fixed" => Type::Fixed,
        "string" => Type::String,
        "object" => Type::Object,
        "new_id" => Type::NewId,
        "array" => Type::Array,
        "fd" => Type::Fd,
        "destructor" => Type::Destructor,
        e => panic!("Unexpected type: {}", e),
    }
}

fn parse_entry<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Entry {
    let mut entry = Entry::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => entry.name = attr.value,
            "value" => {
                entry.value = if attr.value.starts_with("0x") {
                    u32::from_str_radix(&attr.value[2..], 16).unwrap()
                } else {
                    attr.value.parse().unwrap()
                };
            }
            "since" => entry.since = attr.value.parse().unwrap(),
            "summary" => {
                entry.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => entry.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected token: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "entry" => break,
            _ => {}
        }
    }

    entry
}
<|endoftext|>


<commit_before>/*!
Window-wrangling, polygon-pushing and input-grabbing.

*/
#![crate_name="calx_backend"]
#![feature(collections, old_io, std_misc)]
#![feature(plugin)]
#![plugin(glium_macros)]

extern crate glutin;

#[macro_use]
extern crate glium;
extern crate "calx_util" as util;
extern crate time;
extern crate image;

pub use canvas::{CanvasBuilder, Canvas};
pub use canvas::{Image};
pub use canvas_util::{CanvasUtil};
pub use key::Key;
pub use fonter::{Fonter, Align};
pub use event::{Event, MouseButton};

mod canvas;
mod canvas_util;
mod event;
mod fonter;
mod key;
mod renderer;

#[cfg(target_os = "macos")]
mod scancode_macos;
#[cfg(target_os = "linux")]
mod scancode_linux;
#[cfg(target_os = "windows")]
mod scancode_windows;

mod scancode {
#[cfg(target_os = "macos")]
    pub use scancode_macos::MAP;
#[cfg(target_os = "linux")]
    pub use scancode_linux::MAP;
#[cfg(target_os = "windows")]
    pub use scancode_windows::MAP;
}

/// UI Widget static identifier, unique for a specific site in source code.
#[derive(Copy, Debug, PartialEq)]
pub struct WidgetId {
    filename: &'static str,
    line: usize,
    column: usize,
}

impl WidgetId {
    pub fn new(filename: &'static str, line: usize, column: usize) -> WidgetId {
        WidgetId {
            filename: filename,
            line: line,
            column: column,
        }
    }

    pub fn dummy() -> WidgetId {
        WidgetId {
            filename: "n/a",
            line: 666666,
            column: 666666,
        }
    }
}

#[macro_export]
/// Generate a static identifier for the current source code position. Used
/// with imgui API.
macro_rules! widget_id {
    () => {
        // XXX: Assuming the crate user renames 'calx_backend' to 'backend'
        // when declaring the extern crate, since the app that does use this
        // does that. This is extremely wrong and bad to assume. Don't know
        // how to do this right.
        backend::WidgetId::new(concat!(module_path!(), "/", file!()), line!(), column!())
    }
}
<commit_msg>Update to latest Rust<commit_after>/*!
Window-wrangling, polygon-pushing and input-grabbing.

*/
#![crate_name="calx_backend"]
#![feature(collections, old_io, std_misc)]
#![feature(custom_attribute)]
#![feature(plugin)]
#![plugin(glium_macros)]

extern crate glutin;

#[macro_use]
extern crate glium;
extern crate "calx_util" as util;
extern crate time;
extern crate image;

pub use canvas::{CanvasBuilder, Canvas};
pub use canvas::{Image};
pub use canvas_util::{CanvasUtil};
pub use key::Key;
pub use fonter::{Fonter, Align};
pub use event::{Event, MouseButton};

mod canvas;
mod canvas_util;
mod event;
mod fonter;
mod key;
mod renderer;

#[cfg(target_os = "macos")]
mod scancode_macos;
#[cfg(target_os = "linux")]
mod scancode_linux;
#[cfg(target_os = "windows")]
mod scancode_windows;

mod scancode {
#[cfg(target_os = "macos")]
    pub use scancode_macos::MAP;
#[cfg(target_os = "linux")]
    pub use scancode_linux::MAP;
#[cfg(target_os = "windows")]
    pub use scancode_windows::MAP;
}

/// UI Widget static identifier, unique for a specific site in source code.
#[derive(Copy, Debug, PartialEq)]
pub struct WidgetId {
    filename: &'static str,
    line: usize,
    column: usize,
}

impl WidgetId {
    pub fn new(filename: &'static str, line: usize, column: usize) -> WidgetId {
        WidgetId {
            filename: filename,
            line: line,
            column: column,
        }
    }

    pub fn dummy() -> WidgetId {
        WidgetId {
            filename: "n/a",
            line: 666666,
            column: 666666,
        }
    }
}

#[macro_export]
/// Generate a static identifier for the current source code position. Used
/// with imgui API.
macro_rules! widget_id {
    () => {
        // XXX: Assuming the crate user renames 'calx_backend' to 'backend'
        // when declaring the extern crate, since the app that does use this
        // does that. This is extremely wrong and bad to assume. Don't know
        // how to do this right.
        backend::WidgetId::new(concat!(module_path!(), "/", file!()), line!(), column!())
    }
}
<|endoftext|>


<commit_before>use bencher::bench::benchmark;
use bencher::stats::Summary;

extern crate csv;
extern crate weld;
extern crate weld_common;
extern crate libc;

mod bencher;

use self::weld_common::WeldRuntimeErrno;

use self::weld::{weld_conf_new, weld_conf_set, weld_conf_free};
use self::weld::{weld_error_code, weld_error_free};
use self::weld::{weld_value_new, weld_value_data, weld_value_free};
use self::weld::{weld_module_compile, weld_module_run, weld_module_free};
use self::weld::{WeldModule, WeldValue, WeldConf, WeldError};

use std::env;
use std::ffi::CString;
use self::libc::{c_char, c_void};

use bencher::Bencher;

#[derive(Clone)]
#[allow(dead_code)]
struct WeldVec<T> {
    data: *const T,
    len: i64,
}

/// Returns a configuration which uses several threads.
fn benchmark_conf() -> *mut WeldConf {
    let conf = weld_conf_new();
    let key = CString::new("weld.threads").unwrap().into_raw() as *const c_char;
    let value = CString::new("1").unwrap().into_raw() as *const c_char;
    unsafe { weld_conf_set(conf, key, value) };

    let key = CString::new("weld.memory.limit").unwrap().into_raw() as *const c_char;
    let value = CString::new("8589934592").unwrap().into_raw() as *const c_char;
    unsafe { weld_conf_set(conf, key, value) };
    conf
}

/// Returns a compiled, runnable Weld module.
unsafe fn compile_program(code: &str) -> Result<*mut WeldModule, ()> {
    let code = CString::new(code).unwrap();
    let conf = benchmark_conf();

    let mut err = std::ptr::null_mut();
    let module = weld_module_compile(code.into_raw() as *const c_char,
                                     conf,
                                     &mut err as *mut *mut WeldError);

    if weld_error_code(err) != WeldRuntimeErrno::Success {
        weld_conf_free(conf);
        return Err(());
    }
    weld_error_free(err);
    Ok(module)
}

/// Runs a `WeldModule` and returns either a `WeldValue` or `WeldError`, depending on whether the
/// run was successful.
unsafe fn run_module<T>(module: *mut WeldModule,
                        ptr: &T)
                        -> Result<*mut WeldValue, *mut WeldError> {
    let input_value = weld_value_new(ptr as *const _ as *const c_void);
    let conf = benchmark_conf();
    let mut err = std::ptr::null_mut();

    // Timing information per run for debugging.
    use std::time::Instant;
    let s = Instant::now();

    let ret_value = weld_module_run(module, conf, input_value, &mut err as *mut *mut WeldError);

    let dur = s.elapsed();
    let dur = dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64);
    let dur = dur / 1_000_000;
    println!("{} ms", dur);

    // Free the input value wrapper.
    weld_value_free(input_value);
    weld_conf_free(conf);

    if weld_error_code(err) != WeldRuntimeErrno::Success {
        Err(err)
    } else {
        Ok(ret_value)
    }
}

fn bench_vector_sum(bench: &mut Bencher) {
    #[allow(dead_code)]
    struct Args {
        x: WeldVec<i32>,
        y: WeldVec<i32>,
    }

    let code = include_str!("benchmarks/vector_sum.weld");

    // 100MB of data
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    let x: Vec<i32> = vec![4; size as usize];
    let y: Vec<i32> = vec![5; size as usize];

    let ref args = Args {
        x: WeldVec {
            data: x.as_ptr() as *const i32,
            len: size as i64,
        },
        y: WeldVec {
            data: y.as_ptr() as *const i32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // Run once to check correctness/warm up.
    let ret_value = unsafe { run_module(module, args).unwrap() };
    let data = unsafe { weld_value_data(ret_value) as *const WeldVec<i32> };
    let result = unsafe { (*data).clone() };

    assert_eq!(result.len, size as i64);
    for i in 0..(result.len as isize) {
        assert_eq!(unsafe { *result.data.offset(i) },
                   x[i as usize] + y[i as usize]);
    }
    unsafe { weld_value_free(ret_value) };

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });

    unsafe { weld_module_free(module) };
}

fn bench_map_reduce(bench: &mut Bencher) {
    let code = include_str!("benchmarks/map_reduce.weld");

    // 100MB of data
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    let x: Vec<i32> = vec![4; size as usize];

    let ref args = WeldVec {
        data: x.as_ptr() as *const i32,
        len: size as i64,
    };

    let module = unsafe { compile_program(code).unwrap() };

    // Run once to check correctness/warm up.
    let ret_value = unsafe { run_module(module, args).unwrap() };
    let data = unsafe { weld_value_data(ret_value) as *const i32 };
    let result = unsafe { *data };

    let expect = x[0] * 4 * (x.len() as i32);
    assert_eq!(result, expect);
    unsafe { weld_value_free(ret_value) };

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

fn bench_tpch_q1(bench: &mut Bencher) {
    let code = include_str!("benchmarks/tpch/q1.weld");

    #[allow(dead_code)]
    struct Args {
        l_returnflag: WeldVec<i8>,
        l_linestatus: WeldVec<i8>,
        l_quantity: WeldVec<f32>,
        l_ep: WeldVec<f32>,
        l_discount: WeldVec<f32>,
        l_shipdate: WeldVec<i32>,
        l_tax: WeldVec<f32>,
    }

    #[allow(dead_code)]
    struct ReturnValue {
        l_returnflag: i8,
        l_linestatus: i8,
        sum_qty: f32,
        sum_base_price: f32,
        sum_disc_price: f32,
        sum_charge: f32,
        avg_qty: f32,
        avg_price: f32,
        count_order: i32,
    }

    // 100MB of data per column.
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    // Set values so all predicates pass.
    let l_returnflag: Vec<i8> = vec![1; size ];
    let l_linestatus: Vec<i8> = vec![1; size ];
    let l_quantity: Vec<f32> = vec![20.0; size ];
    let l_ep: Vec<f32> = vec![100.0; size];
    let l_discount: Vec<f32> = vec![6.0; size ];
    let l_shipdate: Vec<i32> = vec![19940505; size ];
    let l_tax: Vec<f32> = vec![6.0; size ];

    let ref args = Args {
        l_returnflag: WeldVec {
            data: l_returnflag.as_ptr() as *const i8,
            len: size as i64,
        },
        l_linestatus: WeldVec {
            data: l_linestatus.as_ptr() as *const i8,
            len: size as i64,
        },
        l_quantity: WeldVec {
            data: l_quantity.as_ptr() as *const f32,
            len: size as i64,
        },
        l_ep: WeldVec {
            data: l_ep.as_ptr() as *const f32,
            len: size as i64,
        },
        l_discount: WeldVec {
            data: l_discount.as_ptr() as *const f32,
            len: size as i64,
        },
        l_shipdate: WeldVec {
            data: l_shipdate.as_ptr() as *const i32,
            len: size as i64,
        },
        l_tax: WeldVec {
            data: l_tax.as_ptr() as *const f32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // TODO(shoumik)
    // Run once to check correctness/warm up.
    //
    // let ret_value = unsafe { run_module(module, args).unwrap() };
    // let data = unsafe { weld_value_data(ret_value) as *const i32 };
    // let result = unsafe { *data };
    // unsafe { weld_value_free(ret_value) };
    //

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

fn bench_tpch_q6(bench: &mut Bencher) {
    let code = include_str!("benchmarks/tpch/q6.weld");

    #[allow(dead_code)]
    struct Args {
        l_shipdate: WeldVec<i32>,
        l_discount: WeldVec<f32>,
        l_quantity: WeldVec<f32>,
        l_ep: WeldVec<f32>,
    }

    // 100MB of data per column.
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    // Set values so all predicates pass.
    let l_shipdate: Vec<i32> = vec![19940505; size ];
    let l_discount: Vec<f32> = vec![6.0; size ];
    let l_quantity: Vec<f32> = vec![20.0; size ];
    let l_ep: Vec<f32> = vec![100.0; size];

    // Since all predicates pass, this is the result
    // let expect = l_ep[0] * l_discount[0] * (size as f32);

    let ref args = Args {
        l_shipdate: WeldVec {
            data: l_shipdate.as_ptr() as *const i32,
            len: size as i64,
        },
        l_discount: WeldVec {
            data: l_discount.as_ptr() as *const f32,
            len: size as i64,
        },
        l_quantity: WeldVec {
            data: l_quantity.as_ptr() as *const f32,
            len: size as i64,
        },
        l_ep: WeldVec {
            data: l_ep.as_ptr() as *const f32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // TODO(shoumik)
    // Run once to check correctness/warm up.
    //
    // let ret_value = unsafe { run_module(module, args).unwrap() };
    // let data = unsafe { weld_value_data(ret_value) as *const f32 };
    // let result = unsafe { *data };
    // assert_eq!(result, expect);
    // unsafe { weld_value_free(ret_value) };
    //

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

// Drives the benchmarking.

/// Formats a time in ns as a value in ms.
fn format_ns(x: f64) -> String {
    format!("{:.4}", x / 1000000_f64)
}

fn run_benchmark<W: std::io::Write>(writer: &mut csv::Writer<W>,
                                    bench: &(&str, fn(&mut bencher::Bencher))) {
    let Summary { min, max, mean, median, std_dev, .. } = benchmark(bench.1).ns_iter_summ;
    let record = (bench.0,
                  "weld",
                  format_ns(mean),
                  format_ns(min),
                  format_ns(max),
                  format_ns(median),
                  format_ns(std_dev));
    let result = writer.encode(record);
    assert!(result.is_ok());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let benches: Vec<(&str, fn(&mut bencher::Bencher))> =
        vec![("bench_vector_sum", bench_vector_sum),
             ("bench_map_reduce", bench_map_reduce),
             ("bench_tpch_q1", bench_tpch_q1),
             ("bench_tpch_q6", bench_tpch_q6)];

    let ref mut wtr = csv::Writer::from_file("bench.csv").unwrap();
    // Encode the CSV header.
    let result =
        wtr.encode(("name",
                    "config",
                    "mean(ms)",
                    "min(ms)",
                    "max(ms)",
                    "median(ms)",
                    "std_dev(ms)"));
    assert!(result.is_ok());

    println!("");
    println!("running benchmarks");
    let mut measured = 0;
    for t in benches.iter() {
        if args.len() > 1 {
            if !t.0.contains(args[1].as_str()) {
                println!("{} ... \x1b[0;33mignored\x1b[0m", t.0);
                continue;
            }
        }
        print!("{} ... ", t.0);
        run_benchmark(wtr, t);
        println!("\x1b[0;32mok\x1b[0m");
        measured += 1;
    }

    println!("");
    println!("test result: \x1b[0;32mok\x1b[0m. 0 passed; 0 failed; {} ignored; {} measured",
             benches.len() - measured,
             measured);
    println!("");
}
<commit_msg>Small benching fix<commit_after>use bencher::bench::benchmark;
use bencher::stats::Summary;

extern crate csv;
extern crate weld;
extern crate weld_common;
extern crate libc;

mod bencher;

use self::weld_common::WeldRuntimeErrno;

use self::weld::{weld_conf_new, weld_conf_set, weld_conf_free};
use self::weld::{weld_error_code, weld_error_free};
use self::weld::{weld_value_new, weld_value_data, weld_value_free};
use self::weld::{weld_module_compile, weld_module_run, weld_module_free};
use self::weld::{WeldModule, WeldValue, WeldConf, WeldError};

use std::env;
use std::ffi::CString;
use self::libc::{c_char, c_void};

use bencher::Bencher;

#[derive(Clone)]
#[allow(dead_code)]
struct WeldVec<T> {
    data: *const T,
    len: i64,
}

/// Returns a configuration which uses several threads.
fn benchmark_conf() -> *mut WeldConf {
    let conf = weld_conf_new();
    let key = CString::new("weld.threads").unwrap().into_raw() as *const c_char;
    let value = CString::new("4").unwrap().into_raw() as *const c_char;
    unsafe { weld_conf_set(conf, key, value) };

    let key = CString::new("weld.memory.limit").unwrap().into_raw() as *const c_char;
    let value = CString::new("8589934592").unwrap().into_raw() as *const c_char;
    unsafe { weld_conf_set(conf, key, value) };
    conf
}

/// Returns a compiled, runnable Weld module.
unsafe fn compile_program(code: &str) -> Result<*mut WeldModule, ()> {
    let code = CString::new(code).unwrap();
    let conf = benchmark_conf();

    let mut err = std::ptr::null_mut();
    let module = weld_module_compile(code.into_raw() as *const c_char,
                                     conf,
                                     &mut err as *mut *mut WeldError);

    if weld_error_code(err) != WeldRuntimeErrno::Success {
        weld_conf_free(conf);
        return Err(());
    }
    weld_error_free(err);
    Ok(module)
}

/// Runs a `WeldModule` and returns either a `WeldValue` or `WeldError`, depending on whether the
/// run was successful.
unsafe fn run_module<T>(module: *mut WeldModule,
                        ptr: &T)
                        -> Result<*mut WeldValue, *mut WeldError> {
    let input_value = weld_value_new(ptr as *const _ as *const c_void);
    let conf = benchmark_conf();
    let mut err = std::ptr::null_mut();

    // Timing information per run for debugging.
    use std::time::Instant;
    let s = Instant::now();

    let ret_value = weld_module_run(module, conf, input_value, &mut err as *mut *mut WeldError);

    let dur = s.elapsed();
    let dur = dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64);
    let dur = dur / 1_000_000;
    println!("{} ms", dur);

    // Free the input value wrapper.
    weld_value_free(input_value);
    weld_conf_free(conf);

    if weld_error_code(err) != WeldRuntimeErrno::Success {
        Err(err)
    } else {
        Ok(ret_value)
    }
}

fn bench_vector_sum(bench: &mut Bencher) {
    #[allow(dead_code)]
    struct Args {
        x: WeldVec<i32>,
        y: WeldVec<i32>,
    }

    let code = include_str!("benchmarks/vector_sum.weld");

    // 100MB of data
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    let x: Vec<i32> = vec![4; size as usize];
    let y: Vec<i32> = vec![5; size as usize];

    let ref args = Args {
        x: WeldVec {
            data: x.as_ptr() as *const i32,
            len: size as i64,
        },
        y: WeldVec {
            data: y.as_ptr() as *const i32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // Run once to check correctness/warm up.
    let ret_value = unsafe { run_module(module, args).unwrap() };
    let data = unsafe { weld_value_data(ret_value) as *const WeldVec<i32> };
    let result = unsafe { (*data).clone() };

    assert_eq!(result.len, size as i64);
    for i in 0..(result.len as isize) {
        assert_eq!(unsafe { *result.data.offset(i) },
                   x[i as usize] + y[i as usize]);
    }
    unsafe { weld_value_free(ret_value) };

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });

    unsafe { weld_module_free(module) };
}

fn bench_map_reduce(bench: &mut Bencher) {
    let code = include_str!("benchmarks/map_reduce.weld");

    // 100MB of data
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    let x: Vec<i32> = vec![4; size as usize];

    let ref args = WeldVec {
        data: x.as_ptr() as *const i32,
        len: size as i64,
    };

    let module = unsafe { compile_program(code).unwrap() };

    // Run once to check correctness/warm up.
    let ret_value = unsafe { run_module(module, args).unwrap() };
    let data = unsafe { weld_value_data(ret_value) as *const i32 };
    let result = unsafe { *data };

    let expect = x[0] * 4 * (x.len() as i32);
    assert_eq!(result, expect);
    unsafe { weld_value_free(ret_value) };

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

fn bench_tpch_q1(bench: &mut Bencher) {
    let code = include_str!("benchmarks/tpch/q1.weld");

    #[allow(dead_code)]
    struct Args {
        l_returnflag: WeldVec<i8>,
        l_linestatus: WeldVec<i8>,
        l_quantity: WeldVec<f32>,
        l_ep: WeldVec<f32>,
        l_discount: WeldVec<f32>,
        l_shipdate: WeldVec<i32>,
        l_tax: WeldVec<f32>,
    }

    #[allow(dead_code)]
    struct ReturnValue {
        l_returnflag: i8,
        l_linestatus: i8,
        sum_qty: f32,
        sum_base_price: f32,
        sum_disc_price: f32,
        sum_charge: f32,
        avg_qty: f32,
        avg_price: f32,
        count_order: i32,
    }

    // 100MB of data per column.
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    // Set values so all predicates pass.
    let l_returnflag: Vec<i8> = vec![1; size ];
    let l_linestatus: Vec<i8> = vec![1; size ];
    let l_quantity: Vec<f32> = vec![20.0; size ];
    let l_ep: Vec<f32> = vec![100.0; size];
    let l_discount: Vec<f32> = vec![6.0; size ];
    let l_shipdate: Vec<i32> = vec![19940505; size ];
    let l_tax: Vec<f32> = vec![6.0; size ];

    let ref args = Args {
        l_returnflag: WeldVec {
            data: l_returnflag.as_ptr() as *const i8,
            len: size as i64,
        },
        l_linestatus: WeldVec {
            data: l_linestatus.as_ptr() as *const i8,
            len: size as i64,
        },
        l_quantity: WeldVec {
            data: l_quantity.as_ptr() as *const f32,
            len: size as i64,
        },
        l_ep: WeldVec {
            data: l_ep.as_ptr() as *const f32,
            len: size as i64,
        },
        l_discount: WeldVec {
            data: l_discount.as_ptr() as *const f32,
            len: size as i64,
        },
        l_shipdate: WeldVec {
            data: l_shipdate.as_ptr() as *const i32,
            len: size as i64,
        },
        l_tax: WeldVec {
            data: l_tax.as_ptr() as *const f32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // TODO(shoumik)
    // Run once to check correctness/warm up.
    //
    // let ret_value = unsafe { run_module(module, args).unwrap() };
    // let data = unsafe { weld_value_data(ret_value) as *const i32 };
    // let result = unsafe { *data };
    // unsafe { weld_value_free(ret_value) };
    //

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

fn bench_tpch_q6(bench: &mut Bencher) {
    let code = include_str!("benchmarks/tpch/q6.weld");

    #[allow(dead_code)]
    struct Args {
        l_shipdate: WeldVec<i32>,
        l_discount: WeldVec<f32>,
        l_quantity: WeldVec<f32>,
        l_ep: WeldVec<f32>,
    }

    // 100MB of data per column.
    let data_size: usize = 2 << 26;
    let size: usize = data_size / std::mem::size_of::<i32>();

    // Set values so all predicates pass.
    let l_shipdate: Vec<i32> = vec![19940505; size ];
    let l_discount: Vec<f32> = vec![6.0; size ];
    let l_quantity: Vec<f32> = vec![20.0; size ];
    let l_ep: Vec<f32> = vec![100.0; size];

    // Since all predicates pass, this is the result
    // let expect = l_ep[0] * l_discount[0] * (size as f32);

    let ref args = Args {
        l_shipdate: WeldVec {
            data: l_shipdate.as_ptr() as *const i32,
            len: size as i64,
        },
        l_discount: WeldVec {
            data: l_discount.as_ptr() as *const f32,
            len: size as i64,
        },
        l_quantity: WeldVec {
            data: l_quantity.as_ptr() as *const f32,
            len: size as i64,
        },
        l_ep: WeldVec {
            data: l_ep.as_ptr() as *const f32,
            len: size as i64,
        },
    };

    let module = unsafe { compile_program(code).unwrap() };

    // TODO(shoumik)
    // Run once to check correctness/warm up.
    //
    // let ret_value = unsafe { run_module(module, args).unwrap() };
    // let data = unsafe { weld_value_data(ret_value) as *const f32 };
    // let result = unsafe { *data };
    // assert_eq!(result, expect);
    // unsafe { weld_value_free(ret_value) };
    //

    bench.iter(|| {
        match unsafe { run_module(module, args) } {
            Ok(v) => unsafe { weld_value_free(v) },
            Err(e) => unsafe { weld_error_free(e) },
        }
    });
}

// Drives the benchmarking.

/// Formats a time in ns as a value in ms.
fn format_ns(x: f64) -> String {
    format!("{:.4}", x / 1000000_f64)
}

fn run_benchmark<W: std::io::Write>(writer: &mut csv::Writer<W>,
                                    bench: &(&str, fn(&mut bencher::Bencher))) {
    let Summary { min, max, mean, median, std_dev, .. } = benchmark(bench.1).ns_iter_summ;
    let record = (bench.0,
                  "weld",
                  format_ns(mean),
                  format_ns(min),
                  format_ns(max),
                  format_ns(median),
                  format_ns(std_dev));
    let result = writer.encode(record);
    assert!(result.is_ok());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let benches: Vec<(&str, fn(&mut bencher::Bencher))> =
        vec![("bench_vector_sum", bench_vector_sum),
             ("bench_map_reduce", bench_map_reduce),
             ("bench_tpch_q1", bench_tpch_q1),
             ("bench_tpch_q6", bench_tpch_q6)];

    let ref mut wtr = csv::Writer::from_file("bench.csv").unwrap();
    // Encode the CSV header.
    let result =
        wtr.encode(("name",
                    "config",
                    "mean(ms)",
                    "min(ms)",
                    "max(ms)",
                    "median(ms)",
                    "std_dev(ms)"));
    assert!(result.is_ok());

    println!("");
    println!("running benchmarks");
    let mut measured = 0;
    for t in benches.iter() {
        if args.len() > 2 {
            if !t.0.contains(args[1].as_str()) {
                println!("{} ... \x1b[0;33mignored\x1b[0m", t.0);
                continue;
            }
        }
        print!("{} ... ", t.0);
        run_benchmark(wtr, t);
        println!("\x1b[0;32mok\x1b[0m");
        measured += 1;
    }

    println!("");
    println!("test result: \x1b[0;32mok\x1b[0m. 0 passed; 0 failed; {} ignored; {} measured",
             benches.len() - measured,
             measured);
    println!("");
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate pcg_rand;
extern crate rand;
extern crate rand_core;
extern crate test;

use pcg_rand::{Pcg32Basic, Pcg64Basic};
use test::Bencher;
use rand::{Rng, XorShiftRng, FromEntropy};
use rand_core::RngCore;

#[bench]
fn pcg32basic_next_u32(b: &mut Bencher) {
    let mut rng = Pcg32Basic::from_entropy();

    b.iter(|| {
        rng.next_u32()
    })
}

#[bench]
fn pcg32basic_fill_bytes(b: &mut Bencher) {
    b.bytes = 1024*1024;
    let mut rng = Pcg32Basic::from_entropy();

    let mut x = vec![0; b.bytes as usize];

    b.iter(|| {
        rng.fill_bytes(x.as_mut_slice())
    })
}

#[bench]
fn xorshift_next_u32(b: &mut Bencher) {
    let mut rng = XorShiftRng::from_entropy();

    b.iter(|| {
        rng.next_u32()
    })
}

#[bench]
fn xorshift_fill_bytes(b: &mut Bencher) {
    b.bytes = 1024*1024;
    let mut rng = XorShiftRng::from_entropy();

    let mut x = vec![0; b.bytes as usize];

    b.iter(|| {
        rng.fill_bytes(x.as_mut_slice())
    })
}

<commit_msg>Removed Pcg64Basic last remains<commit_after>#![feature(test)]

extern crate pcg_rand;
extern crate rand;
extern crate rand_core;
extern crate test;

use pcg_rand::Pcg32Basic;
use test::Bencher;
use rand::{Rng, XorShiftRng, FromEntropy};
use rand_core::RngCore;

#[bench]
fn pcg32basic_next_u32(b: &mut Bencher) {
    let mut rng = Pcg32Basic::from_entropy();

    b.iter(|| {
        rng.next_u32()
    })
}

#[bench]
fn pcg32basic_fill_bytes(b: &mut Bencher) {
    b.bytes = 1024*1024;
    let mut rng = Pcg32Basic::from_entropy();

    let mut x = vec![0; b.bytes as usize];

    b.iter(|| {
        rng.fill_bytes(x.as_mut_slice())
    })
}

#[bench]
fn xorshift_next_u32(b: &mut Bencher) {
    let mut rng = XorShiftRng::from_entropy();

    b.iter(|| {
        rng.next_u32()
    })
}

#[bench]
fn xorshift_fill_bytes(b: &mut Bencher) {
    b.bytes = 1024*1024;
    let mut rng = XorShiftRng::from_entropy();

    let mut x = vec![0; b.bytes as usize];

    b.iter(|| {
        rng.fill_bytes(x.as_mut_slice())
    })
}

<|endoftext|>


<commit_before>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    c.bench_function("handshake", move |b| {
        b.iter(|| {
            let mut pipe =
                quiche::testing::Pipe::with_config(&mut config).unwrap();
            pipe.handshake(&mut buf).unwrap();
        })
    });
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs(
        "stream",
        move |b, &&size| {
            b.iter(|| {
                pipe.client
                    .stream_send(4, &send_buf[..size], false)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    pipe.flush_client(&mut buf).unwrap();

                    let (len, _) = pipe
                        .server
                        .stream_recv(4, &mut recv_buf[recv_len..])
                        .unwrap();
                    recv_len += len;

                    pipe.flush_server(&mut buf).unwrap();
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 5_000_000],
    );
}

fn http3(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    let mut h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();

    let mut s =
        quiche::h3::testing::Session::with_configs(&mut config, &mut h3_config)
            .unwrap();
    s.handshake().unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    let req = [
        quiche::h3::Header::new(":method", "GET"),
        quiche::h3::Header::new(":scheme", "https"),
        quiche::h3::Header::new(":authority", "quic.tech"),
        quiche::h3::Header::new(":path", "/test"),
        quiche::h3::Header::new("user-agent", "quiche-test"),
    ];

    let resp = [
        quiche::h3::Header::new(":status", "200"),
        quiche::h3::Header::new("server", "quiche-test"),
    ];

    c.bench_function_over_inputs(
        "http3",
        move |b, &&size| {
            b.iter(|| {
                s.client
                    .send_request(&mut s.pipe.client, &req, true)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    s.pipe.flush_client(&mut buf).unwrap();

                    match s.server.poll(&mut s.pipe.server) {
                        Ok((stream, quiche::h3::Event::Headers(_))) => {
                            s.server
                                .send_response(
                                    &mut s.pipe.server,
                                    stream,
                                    &resp,
                                    false,
                                )
                                .unwrap();

                            s.server
                                .send_body(
                                    &mut s.pipe.server,
                                    stream,
                                    &send_buf[..size],
                                    true,
                                )
                                .unwrap();
                        },

                        _ => (),
                    }

                    s.pipe.flush_server(&mut buf).unwrap();

                    while let Ok(ev) = s.client.poll(&mut s.pipe.client) {
                        match ev {
                            (_, quiche::h3::Event::Data(data)) => {
                                &mut recv_buf[recv_len..recv_len + data.len()]
                                    .copy_from_slice(&data);
                                recv_len += data.len();
                            },

                            _ => (),
                        };
                    }
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[0, 128_000, 5_000_000],
    );
}

fn make_bench_config() -> quiche::Config {
    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_uni(150);
    config.set_initial_max_streams_bidi(2u64.pow(60) - 1);
    config.set_initial_max_streams_uni(5);
    config.verify_peer(false);

    config
}

criterion_group!(benches, handshake, stream, http3);

criterion_main!(benches);
<commit_msg>benches: add additional buffer sizes for stream and http3 benches<commit_after>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    c.bench_function("handshake", move |b| {
        b.iter(|| {
            let mut pipe =
                quiche::testing::Pipe::with_config(&mut config).unwrap();
            pipe.handshake(&mut buf).unwrap();
        })
    });
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs(
        "stream",
        move |b, &&size| {
            b.iter(|| {
                pipe.client
                    .stream_send(4, &send_buf[..size], false)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    pipe.flush_client(&mut buf).unwrap();

                    let (len, _) = pipe
                        .server
                        .stream_recv(4, &mut recv_buf[recv_len..])
                        .unwrap();
                    recv_len += len;

                    pipe.flush_server(&mut buf).unwrap();
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 256_000, 512_000, 1_000_000, 5_000_000],
    );
}

fn http3(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = make_bench_config();

    let mut h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();

    let mut s =
        quiche::h3::testing::Session::with_configs(&mut config, &mut h3_config)
            .unwrap();
    s.handshake().unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    let req = [
        quiche::h3::Header::new(":method", "GET"),
        quiche::h3::Header::new(":scheme", "https"),
        quiche::h3::Header::new(":authority", "quic.tech"),
        quiche::h3::Header::new(":path", "/test"),
        quiche::h3::Header::new("user-agent", "quiche-test"),
    ];

    let resp = [
        quiche::h3::Header::new(":status", "200"),
        quiche::h3::Header::new("server", "quiche-test"),
    ];

    c.bench_function_over_inputs(
        "http3",
        move |b, &&size| {
            b.iter(|| {
                s.client
                    .send_request(&mut s.pipe.client, &req, true)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    s.pipe.flush_client(&mut buf).unwrap();

                    match s.server.poll(&mut s.pipe.server) {
                        Ok((stream, quiche::h3::Event::Headers(_))) => {
                            s.server
                                .send_response(
                                    &mut s.pipe.server,
                                    stream,
                                    &resp,
                                    false,
                                )
                                .unwrap();

                            s.server
                                .send_body(
                                    &mut s.pipe.server,
                                    stream,
                                    &send_buf[..size],
                                    true,
                                )
                                .unwrap();
                        },

                        _ => (),
                    }

                    s.pipe.flush_server(&mut buf).unwrap();

                    while let Ok(ev) = s.client.poll(&mut s.pipe.client) {
                        match ev {
                            (_, quiche::h3::Event::Data(data)) => {
                                &mut recv_buf[recv_len..recv_len + data.len()]
                                    .copy_from_slice(&data);
                                recv_len += data.len();
                            },

                            _ => (),
                        };
                    }
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 256_000, 512_000, 1_000_000, 5_000_000],
    );
}

fn make_bench_config() -> quiche::Config {
    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_uni(150);
    config.set_initial_max_streams_bidi(2u64.pow(60) - 1);
    config.set_initial_max_streams_uni(5);
    config.verify_peer(false);

    config
}

criterion_group!(benches, handshake, stream, http3);

criterion_main!(benches);
<|endoftext|>