<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::convert;
use crate::ops::{self, ControlFlow};
use crate::result::Result;
use crate::task::Ready;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Maps a `Poll<T>` to `Poll<U>` by applying a function to a contained value.
    ///
    /// # Examples
    ///
    /// Converts a Poll<[String]> into a Poll<[usize]>, consuming
    /// the original:
    ///
    /// [String]: ../../std/string/struct.String.html "String"
    /// ```
    /// # use core::task::Poll;
    /// let poll_some_string = Poll::Ready(String::from("Hello, World!"));
    /// // `Poll::map` takes self *by value*, consuming `poll_some_string`
    /// let poll_some_len = poll_some_string.map(|s| s.len());
    ///
    /// assert_eq!(poll_some_len, Poll::Ready(13));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map(self, f: F) -> Poll
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if the poll is a [`Poll::Ready`] value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let x: Poll<u32> = Poll::Ready(2);
    /// assert_eq!(x.is_ready(), true);
    ///
    /// let x: Poll<u32> = Poll::Pending;
    /// assert_eq!(x.is_ready(), false);
    /// ```
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if the poll is a [`Pending`] value.
    ///
    /// [`Pending`]: Poll::Pending
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let x: Poll<u32> = Poll::Ready(2);
    /// assert_eq!(x.is_pending(), false);
    ///
    /// let x: Poll<u32> = Poll::Pending;
    /// assert_eq!(x.is_pending(), true);
    /// ```
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_pending(&self) -> bool {
        !self.is_ready()
    }

    /// Extracts the successful type of a [`Poll<T>`].
    ///
    /// When combined with the `?` operator, this function will
    /// propogate any [`Poll::Pending`] values to the caller, and
    /// extract the `T` from [`Poll::Ready`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// #![feature(poll_ready)]
    ///
    /// use std::task::{Context, Poll};
    /// use std::future::{self, Future};
    /// use std::pin::Pin;
    ///
    /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
    ///     let mut fut = future::ready(42);
    ///     let fut = Pin::new(&mut fut);
    ///
    ///     let num = fut.poll(cx).ready()?;
    ///     # drop(num);
    ///     // ... use num
    ///
    ///     Poll::Ready(())
    /// }
    /// ```
    #[inline]
    #[unstable(feature = "poll_ready", issue = "89780")]
    pub fn ready(self) -> Ready<T> {
        Ready(self)
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Maps a `Poll<Result<T, E>>` to `Poll<Result<U, E>>` by applying a
    /// function to a contained `Poll::Ready(Ok)` value, leaving all other
    /// variants untouched.
    ///
    /// This function can be used to compose the results of two functions.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Result<u8, _>> = Poll::Ready("12".parse());
    /// let squared = res.map_ok(|n| n * n);
    /// assert_eq!(squared, Poll::Ready(Ok(144)));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok(self, f: F) -> Poll<Result>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Maps a `Poll::Ready<Result<T, E>>` to `Poll::Ready<Result<T, F>>` by
    /// applying a function to a contained `Poll::Ready(Err)` value, leaving all other
    /// variants untouched.
    ///
    /// This function can be used to pass through a successful result while handling
    /// an error.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Result<u8, _>> = Poll::Ready("oops".parse());
    /// let res = res.map_err(|_| 0_u8);
    /// assert_eq!(res, Poll::Ready(Err(0)));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Maps a `Poll<Option<Result<T, E>>>` to `Poll<Option<Result<U, E>>>` by
    /// applying a function to a contained `Poll::Ready(Some(Ok))` value,
    /// leaving all other variants untouched.
    ///
    /// This function can be used to compose the results of two functions.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("12".parse()));
    /// let squared = res.map_ok(|n| n * n);
    /// assert_eq!(squared, Poll::Ready(Some(Ok(144))));
    /// ```
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_ok(self, f: F) -> Poll<Option<Result>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Maps a `Poll::Ready<Option<Result<T, E>>>` to
    /// `Poll::Ready<Option<Result<T, F>>>` by applying a function to a
    /// contained `Poll::Ready(Some(Err))` value, leaving all other variants
    /// untouched.
    ///
    /// This function can be used to pass through a successful result while handling
    /// an error.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("oops".parse()));
    /// let res = res.map_err(|_| 0_u8);
    /// assert_eq!(res, Poll::Ready(Some(Err(0))));
    /// ```
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_err(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    /// Convert to a `Ready` variant.
    ///
    /// # Example
    ///
    /// ```
    /// # use core::task::Poll;
    /// assert_eq!(Poll::from(true), Poll::Ready(true));
    /// ```
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E> ops::Try for Poll<Result<T, E>> {
    type Output = Poll<T>;
    type Residual = Result<convert::Infallible, E>;

    #[inline]
    fn from_output(c: Self::Output) -> Self {
        c.map(Ok)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            Poll::Ready(Ok(x)) => ControlFlow::Continue(Poll::Ready(x)),
            Poll::Ready(Err(e)) => ControlFlow::Break(Err(e)),
            Poll::Pending => ControlFlow::Continue(Poll::Pending),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> {
    #[inline]
    fn from_residual(x: Result<convert::Infallible, E>) -> Self {
        match x {
            Err(e) => Poll::Ready(Err(From::from(e))),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
    type Output = Poll<Option<T>>;
    type Residual = Result<convert::Infallible, E>;

    #[inline]
    fn from_output(c: Self::Output) -> Self {
        c.map(|x| x.map(Ok))
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            Poll::Ready(Some(Ok(x))) => ControlFlow::Continue(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => ControlFlow::Break(Err(e)),
            Poll::Ready(None) => ControlFlow::Continue(Poll::Ready(None)),
            Poll::Pending => ControlFlow::Continue(Poll::Pending),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>>
    for Poll<Option<Result<T, F>>>
{
    #[inline]
    fn from_residual(x: Result<convert::Infallible, E>) -> Self {
        match x {
            Err(e) => Poll::Ready(Some(Err(From::from(e)))),
        }
    }
}
<commit_msg>Rollup merge of #89799 - ast-ral:ready-method-spellck, r=joshtriplett<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::convert;
use crate::ops::{self, ControlFlow};
use crate::result::Result;
use crate::task::Ready;

/// Indicates whether a value is available or if the current task has been
/// scheduled to receive a wakeup instead.
#[must_use = "this `Poll` may be a `Pending` variant, which should be handled"]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub enum Poll<T> {
    /// Represents that a value is immediately ready.
    #[lang = "Ready"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),

    /// Represents that a value is not ready yet.
    ///
    /// When a function returns `Pending`, the function *must* also
    /// ensure that the current task is scheduled to be awoken when
    /// progress can be made.
    #[lang = "Pending"]
    #[stable(feature = "futures_api", since = "1.36.0")]
    Pending,
}

impl<T> Poll<T> {
    /// Maps a `Poll<T>` to `Poll<U>` by applying a function to a contained value.
    ///
    /// # Examples
    ///
    /// Converts a Poll<[String]> into a Poll<[usize]>, consuming
    /// the original:
    ///
    /// [String]: ../../std/string/struct.String.html "String"
    /// ```
    /// # use core::task::Poll;
    /// let poll_some_string = Poll::Ready(String::from("Hello, World!"));
    /// // `Poll::map` takes self *by value*, consuming `poll_some_string`
    /// let poll_some_len = poll_some_string.map(|s| s.len());
    ///
    /// assert_eq!(poll_some_len, Poll::Ready(13));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map(self, f: F) -> Poll
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Returns `true` if the poll is a [`Poll::Ready`] value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let x: Poll<u32> = Poll::Ready(2);
    /// assert_eq!(x.is_ready(), true);
    ///
    /// let x: Poll<u32> = Poll::Pending;
    /// assert_eq!(x.is_ready(), false);
    /// ```
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_ready(&self) -> bool {
        matches!(*self, Poll::Ready(_))
    }

    /// Returns `true` if the poll is a [`Pending`] value.
    ///
    /// [`Pending`]: Poll::Pending
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let x: Poll<u32> = Poll::Ready(2);
    /// assert_eq!(x.is_pending(), false);
    ///
    /// let x: Poll<u32> = Poll::Pending;
    /// assert_eq!(x.is_pending(), true);
    /// ```
    #[inline]
    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn is_pending(&self) -> bool {
        !self.is_ready()
    }

    /// Extracts the successful type of a [`Poll<T>`].
    ///
    /// When combined with the `?` operator, this function will
    /// propagate any [`Poll::Pending`] values to the caller, and
    /// extract the `T` from [`Poll::Ready`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// #![feature(poll_ready)]
    ///
    /// use std::task::{Context, Poll};
    /// use std::future::{self, Future};
    /// use std::pin::Pin;
    ///
    /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
    ///     let mut fut = future::ready(42);
    ///     let fut = Pin::new(&mut fut);
    ///
    ///     let num = fut.poll(cx).ready()?;
    ///     # drop(num);
    ///     // ... use num
    ///
    ///     Poll::Ready(())
    /// }
    /// ```
    #[inline]
    #[unstable(feature = "poll_ready", issue = "89780")]
    pub fn ready(self) -> Ready<T> {
        Ready(self)
    }
}

impl<T, E> Poll<Result<T, E>> {
    /// Maps a `Poll<Result<T, E>>` to `Poll<Result<U, E>>` by applying a
    /// function to a contained `Poll::Ready(Ok)` value, leaving all other
    /// variants untouched.
    ///
    /// This function can be used to compose the results of two functions.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Result<u8, _>> = Poll::Ready("12".parse());
    /// let squared = res.map_ok(|n| n * n);
    /// assert_eq!(squared, Poll::Ready(Ok(144)));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_ok(self, f: F) -> Poll<Result>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Maps a `Poll::Ready<Result<T, E>>` to `Poll::Ready<Result<T, F>>` by
    /// applying a function to a contained `Poll::Ready(Err)` value, leaving all other
    /// variants untouched.
    ///
    /// This function can be used to pass through a successful result while handling
    /// an error.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Result<u8, _>> = Poll::Ready("oops".parse());
    /// let res = res.map_err(|_| 0_u8);
    /// assert_eq!(res, Poll::Ready(Err(0)));
    /// ```
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn map_err(self, f: F) -> Poll<Result<T, U>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T, E> Poll<Option<Result<T, E>>> {
    /// Maps a `Poll<Option<Result<T, E>>>` to `Poll<Option<Result<U, E>>>` by
    /// applying a function to a contained `Poll::Ready(Some(Ok))` value,
    /// leaving all other variants untouched.
    ///
    /// This function can be used to compose the results of two functions.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("12".parse()));
    /// let squared = res.map_ok(|n| n * n);
    /// assert_eq!(squared, Poll::Ready(Some(Ok(144))));
    /// ```
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_ok(self, f: F) -> Poll<Option<Result>>
    where
        F: FnOnce(T) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(f(t)))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    /// Maps a `Poll::Ready<Option<Result<T, E>>>` to
    /// `Poll::Ready<Option<Result<T, F>>>` by applying a function to a
    /// contained `Poll::Ready(Some(Err))` value, leaving all other variants
    /// untouched.
    ///
    /// This function can be used to pass through a successful result while handling
    /// an error.
    ///
    /// # Examples
    ///
    /// ```
    /// # use core::task::Poll;
    /// let res: Poll<Option<Result<u8, _>>> = Poll::Ready(Some("oops".parse()));
    /// let res = res.map_err(|_| 0_u8);
    /// assert_eq!(res, Poll::Ready(Some(Err(0))));
    /// ```
    #[stable(feature = "poll_map", since = "1.51.0")]
    pub fn map_err(self, f: F) -> Poll<Option<Result<T, U>>>
    where
        F: FnOnce(E) -> U,
    {
        match self {
            Poll::Ready(Some(Ok(t))) => Poll::Ready(Some(Ok(t))),
            Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(f(e)))),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
    /// Convert to a `Ready` variant.
    ///
    /// # Example
    ///
    /// ```
    /// # use core::task::Poll;
    /// assert_eq!(Poll::from(true), Poll::Ready(true));
    /// ```
    fn from(t: T) -> Poll<T> {
        Poll::Ready(t)
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E> ops::Try for Poll<Result<T, E>> {
    type Output = Poll<T>;
    type Residual = Result<convert::Infallible, E>;

    #[inline]
    fn from_output(c: Self::Output) -> Self {
        c.map(Ok)
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            Poll::Ready(Ok(x)) => ControlFlow::Continue(Poll::Ready(x)),
            Poll::Ready(Err(e)) => ControlFlow::Break(Err(e)),
            Poll::Pending => ControlFlow::Continue(Poll::Pending),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> {
    #[inline]
    fn from_residual(x: Result<convert::Infallible, E>) -> Self {
        match x {
            Err(e) => Poll::Ready(Err(From::from(e))),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
    type Output = Poll<Option<T>>;
    type Residual = Result<convert::Infallible, E>;

    #[inline]
    fn from_output(c: Self::Output) -> Self {
        c.map(|x| x.map(Ok))
    }

    #[inline]
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            Poll::Ready(Some(Ok(x))) => ControlFlow::Continue(Poll::Ready(Some(x))),
            Poll::Ready(Some(Err(e))) => ControlFlow::Break(Err(e)),
            Poll::Ready(None) => ControlFlow::Continue(Poll::Ready(None)),
            Poll::Pending => ControlFlow::Continue(Poll::Pending),
        }
    }
}

#[unstable(feature = "try_trait_v2", issue = "84277")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>>
    for Poll<Option<Result<T, F>>>
{
    #[inline]
    fn from_residual(x: Result<convert::Infallible, E>) -> Self {
        match x {
            Err(e) => Poll::Ready(Some(Err(From::from(e)))),
        }
    }
}
<|endoftext|>


<commit_before>//! Define break;

use petgraph::graph::NodeIndex;
use std::collections::HashMap;

use libsmt::backends::smtlib2::{SMTLib2, SMTProc};
use libsmt::backends::backend::SMTBackend;
use libsmt::logics::qf_abv;
use libsmt::theories::bitvec;

use crate::memory::memory::Memory;

use crate::regstore::regstore::{RegStore, RegStoreAPI};
//use regstore::regfile::RuneRegFile;

use crate::context::context::{Context, ContextAPI, Evaluate, RegisterRead, RegisterWrite, MemoryRead, MemoryWrite};

#[derive(Clone, Debug)]
pub struct RuneContext<Mem, Reg>
    where Mem: Memory,
          Reg: RegStore
{
    ip: u64,
    pub solver: SMTLib2<qf_abv::QF_ABV>,
    regstore: Reg,
    mem: Mem,
    e_old: Option<NodeIndex>,
    e_cur: Option<NodeIndex>,
}

impl<Mem, Reg> Context for RuneContext<Mem, Reg>
    where Mem: Memory<VarRef=NodeIndex>,
          Reg: RegStore<VarRef=NodeIndex>
{
    fn set_e_old(&mut self, i: NodeIndex) {
        self.e_old = Some(i);
    }

    fn set_e_cur(&mut self, i: NodeIndex) {
        self.e_cur = Some(i);
    }

    fn e_old(&self) -> NodeIndex {
        assert!(self.e_old.is_some(), "e_old accessed before being set!");
        self.e_old.unwrap()
    }

    fn e_cur(&self) -> NodeIndex {
        assert!(self.e_cur.is_some(), "e_cur accessed before being set!");
        self.e_cur.unwrap()
    }

    fn ip(&self) -> u64 {
        self.ip
    }

    fn is_symbolic(&self) -> bool {
        true
    }

    fn increment_ip(&mut self, by: u64) {
        self.ip += by;
    }

    fn set_ip(&mut self, to: u64) {
        self.ip = to;
    }

    fn define_const(&mut self, c: u64, size: usize) -> NodeIndex {
        self.solver.new_const(bitvec::OpCodes::Const(c, size))
    }

    fn alias_of(&self, reg: String) -> Option<String> {
        self.regstore.get_reg_entry(&reg).alias.clone()
    }

    fn solve<S: SMTProc>(&mut self, p: &mut S) -> HashMap<NodeIndex, u64> {
        self.solver.solve(p).expect("No satisfying solution.")
    }

    fn var_named<T: AsRef<str>>(&self, _var: T) -> Option<NodeIndex> {
        None
    }
}

impl<Mem, Reg> RegisterRead for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn reg_read<T: AsRef<str>>(&mut self, reg: T) -> NodeIndex {
        self.regstore.read(reg.as_ref(), &mut self.solver)
    }
}

impl<Mem, Reg> RegisterWrite for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn reg_write<T: AsRef<str>>(&mut self, reg: T, source: NodeIndex) {
        let e_old = self.regstore.write(reg.as_ref(), source);
        // XXX: THIS IS A HACK!
        // IF NOT REG
        if !reg.as_ref().to_owned().ends_with('f') {
            self.e_old = e_old;
            self.e_cur = Some(source);
        }
    }
}

impl<Mem, Reg> MemoryRead for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn mem_read(&mut self, addr: NodeIndex, read_size: usize) -> NodeIndex {
        // Assert read size is multiple of 8
        assert_eq!(read_size%8, 0, "Read Size is not divisible by 8");
        self.mem.read(addr, read_size, &mut self.solver)
    }
}

impl<Mem, Reg> MemoryWrite for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn mem_write(&mut self, addr: NodeIndex, data: NodeIndex, write_size: usize) {
        // Assert write size is multiple of 8
        assert_eq!(write_size%8, 0, "Write Size is not divisible by 8");
        self.mem.write(addr, data, write_size, &mut self.solver);
    }
}

impl<Mem, Reg> Evaluate for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;
    type IFn = qf_abv::QF_ABV_Fn;

    fn eval<T, Q>(&mut self, smt_fn: T, operands: Q) -> Self::VarRef
        where T: Into<Self::IFn>,
              Q: AsRef<[Self::VarRef]>
    {
        // TODO: Add extract / concat to ensure that the registers are of compatible
        // sizes for operations.
        self.solver.assert(smt_fn, operands.as_ref())
    }
}

impl<Mem, Reg> ContextAPI for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex> + RegStoreAPI
{
    fn set_reg_as_const<T: AsRef<str>>(&mut self, reg: T, val: u64) -> NodeIndex {
        if let Some(cval) = self.regstore.get_reg_ref(reg.as_ref()) {
            cval
        } else {
            let cval = self.define_const(val, 64);
            self.regstore.set_reg(reg.as_ref(), cval);
            cval
        }
    }

    fn set_reg_as_sym<T: AsRef<str>>(&mut self, reg: T) -> NodeIndex {
        let sym = self.solver.new_var(Some(reg.as_ref()), qf_abv::bv_sort(64));
        self.regstore.set_reg(reg.as_ref(), sym);
        // self.syms.insert(reg.as_ref().to_owned(), sym);

        sym
    }

    fn set_mem_as_const(&mut self, addr: u64, val: u64, write_size: usize) -> NodeIndex {
        // Assert that memory var is in chunks of 8
        assert_eq!(write_size%8, 0, "Write size is not divisible by 8!");

        let addr = self.define_const(addr, 64);
        let cval = self.define_const(val, write_size);
        self.mem_write(addr, cval, write_size);

        cval
    }

    fn set_mem_as_sym(&mut self, addr: u64, write_size: usize) -> NodeIndex {
        // Assert that memory var is in chunks of 8
        assert_eq!(write_size%8, 0, "Write size is not divisible by 8!");

        let key = format!("mem_{}_{}", addr, write_size/8);
        let sym = self.solver.new_var(Some(&key), qf_abv::bv_sort(write_size));
        let addr = self.define_const(addr, 64);

        self.mem_write(addr, sym, write_size);
        // self.syms.insert(key, sym);

        sym
    }

    fn zero_registers(&mut self) {
        let cval = Some(self.define_const(0, 64));
        for reg in &mut self.regstore.get_regs() {
            if reg.is_none() {
                *reg = cval;
            }
        }
    }

    fn registers(&self) -> Vec<String> {
        unimplemented!();
    }
}

impl<Mem, Reg> RuneContext<Mem, Reg>
where Mem: Memory,
      Reg: RegStore
{
    pub fn new(ip: Option<u64>,
               mem: Mem,
               regstore: Reg,
               solver: SMTLib2<qf_abv::QF_ABV>)
               -> RuneContext<Mem, Reg> {
        RuneContext {
            ip: ip.unwrap_or(0),
            mem: mem,
            regstore: regstore,
            solver: solver,
            e_old: None,
            e_cur: None,
        }
    }
}

mod test {
    use super::*;

    use libsmt::logics::qf_abv;
    use libsmt::backends::smtlib2::SMTLib2;

    use crate::memory::seg_mem::SegMem;
    use crate::regstore::regfile::RuneRegFile;

    use r2api::structs::Endian;

    // #[test]
    fn teting_memory_my_dude() {
        let mut lreginfo = Default::default();
        let regstore = RuneRegFile::new(&mut lreginfo);

        let mut mem = SegMem::new(64, Endian::Big);
		let mut smt = SMTLib2::new(Some(qf_abv::QF_ABV));
		mem.init_memory(&mut smt);

        let _ctx = RuneContext::new(Some(0x9000), mem, regstore, smt);
    }
}
<commit_msg>Fix a typo<commit_after>//! Define break;

use petgraph::graph::NodeIndex;
use std::collections::HashMap;

use libsmt::backends::smtlib2::{SMTLib2, SMTProc};
use libsmt::backends::backend::SMTBackend;
use libsmt::logics::qf_abv;
use libsmt::theories::bitvec;

use crate::memory::memory::Memory;

use crate::regstore::regstore::{RegStore, RegStoreAPI};
//use regstore::regfile::RuneRegFile;

use crate::context::context::{Context, ContextAPI, Evaluate, RegisterRead, RegisterWrite, MemoryRead, MemoryWrite};

#[derive(Clone, Debug)]
pub struct RuneContext<Mem, Reg>
    where Mem: Memory,
          Reg: RegStore
{
    ip: u64,
    pub solver: SMTLib2<qf_abv::QF_ABV>,
    regstore: Reg,
    mem: Mem,
    e_old: Option<NodeIndex>,
    e_cur: Option<NodeIndex>,
}

impl<Mem, Reg> Context for RuneContext<Mem, Reg>
    where Mem: Memory<VarRef=NodeIndex>,
          Reg: RegStore<VarRef=NodeIndex>
{
    fn set_e_old(&mut self, i: NodeIndex) {
        self.e_old = Some(i);
    }

    fn set_e_cur(&mut self, i: NodeIndex) {
        self.e_cur = Some(i);
    }

    fn e_old(&self) -> NodeIndex {
        assert!(self.e_old.is_some(), "e_old accessed before being set!");
        self.e_old.unwrap()
    }

    fn e_cur(&self) -> NodeIndex {
        assert!(self.e_cur.is_some(), "e_cur accessed before being set!");
        self.e_cur.unwrap()
    }

    fn ip(&self) -> u64 {
        self.ip
    }

    fn is_symbolic(&self) -> bool {
        true
    }

    fn increment_ip(&mut self, by: u64) {
        self.ip += by;
    }

    fn set_ip(&mut self, to: u64) {
        self.ip = to;
    }

    fn define_const(&mut self, c: u64, size: usize) -> NodeIndex {
        self.solver.new_const(bitvec::OpCodes::Const(c, size))
    }

    fn alias_of(&self, reg: String) -> Option<String> {
        self.regstore.get_reg_entry(&reg).alias.clone()
    }

    fn solve<S: SMTProc>(&mut self, p: &mut S) -> HashMap<NodeIndex, u64> {
        self.solver.solve(p).expect("No satisfying solution.")
    }

    fn var_named<T: AsRef<str>>(&self, _var: T) -> Option<NodeIndex> {
        None
    }
}

impl<Mem, Reg> RegisterRead for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn reg_read<T: AsRef<str>>(&mut self, reg: T) -> NodeIndex {
        self.regstore.read(reg.as_ref(), &mut self.solver)
    }
}

impl<Mem, Reg> RegisterWrite for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn reg_write<T: AsRef<str>>(&mut self, reg: T, source: NodeIndex) {
        let e_old = self.regstore.write(reg.as_ref(), source);
        // XXX: THIS IS A HACK!
        // IF NOT REG
        if !reg.as_ref().to_owned().ends_with('f') {
            self.e_old = e_old;
            self.e_cur = Some(source);
        }
    }
}

impl<Mem, Reg> MemoryRead for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn mem_read(&mut self, addr: NodeIndex, read_size: usize) -> NodeIndex {
        // Assert read size is multiple of 8
        assert_eq!(read_size%8, 0, "Read Size is not divisible by 8");
        self.mem.read(addr, read_size, &mut self.solver)
    }
}

impl<Mem, Reg> MemoryWrite for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;

    fn mem_write(&mut self, addr: NodeIndex, data: NodeIndex, write_size: usize) {
        // Assert write size is multiple of 8
        assert_eq!(write_size%8, 0, "Write Size is not divisible by 8");
        self.mem.write(addr, data, write_size, &mut self.solver);
    }
}

impl<Mem, Reg> Evaluate for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex>
{
    type VarRef = NodeIndex;
    type IFn = qf_abv::QF_ABV_Fn;

    fn eval<T, Q>(&mut self, smt_fn: T, operands: Q) -> Self::VarRef
        where T: Into<Self::IFn>,
              Q: AsRef<[Self::VarRef]>
    {
        // TODO: Add extract / concat to ensure that the registers are of compatible
        // sizes for operations.
        self.solver.assert(smt_fn, operands.as_ref())
    }
}

impl<Mem, Reg> ContextAPI for RuneContext<Mem, Reg>
where Mem: Memory<VarRef=NodeIndex>,
      Reg: RegStore<VarRef=NodeIndex> + RegStoreAPI
{
    fn set_reg_as_const<T: AsRef<str>>(&mut self, reg: T, val: u64) -> NodeIndex {
        if let Some(cval) = self.regstore.get_reg_ref(reg.as_ref()) {
            cval
        } else {
            let cval = self.define_const(val, 64);
            self.regstore.set_reg(reg.as_ref(), cval);
            cval
        }
    }

    fn set_reg_as_sym<T: AsRef<str>>(&mut self, reg: T) -> NodeIndex {
        let sym = self.solver.new_var(Some(reg.as_ref()), qf_abv::bv_sort(64));
        self.regstore.set_reg(reg.as_ref(), sym);
        // self.syms.insert(reg.as_ref().to_owned(), sym);

        sym
    }

    fn set_mem_as_const(&mut self, addr: u64, val: u64, write_size: usize) -> NodeIndex {
        // Assert that memory var is in chunks of 8
        assert_eq!(write_size%8, 0, "Write size is not divisible by 8!");

        let addr = self.define_const(addr, 64);
        let cval = self.define_const(val, write_size);
        self.mem_write(addr, cval, write_size);

        cval
    }

    fn set_mem_as_sym(&mut self, addr: u64, write_size: usize) -> NodeIndex {
        // Assert that memory var is in chunks of 8
        assert_eq!(write_size%8, 0, "Write size is not divisible by 8!");

        let key = format!("mem_{}_{}", addr, write_size/8);
        let sym = self.solver.new_var(Some(&key), qf_abv::bv_sort(write_size));
        let addr = self.define_const(addr, 64);

        self.mem_write(addr, sym, write_size);
        // self.syms.insert(key, sym);

        sym
    }

    fn zero_registers(&mut self) {
        let cval = Some(self.define_const(0, 64));
        for reg in &mut self.regstore.get_regs() {
            if reg.is_none() {
                *reg = cval;
            }
        }
    }

    fn registers(&self) -> Vec<String> {
        unimplemented!();
    }
}

impl<Mem, Reg> RuneContext<Mem, Reg>
where Mem: Memory,
      Reg: RegStore
{
    pub fn new(ip: Option<u64>,
               mem: Mem,
               regstore: Reg,
               solver: SMTLib2<qf_abv::QF_ABV>)
               -> RuneContext<Mem, Reg> {
        RuneContext {
            ip: ip.unwrap_or(0),
            mem: mem,
            regstore: regstore,
            solver: solver,
            e_old: None,
            e_cur: None,
        }
    }
}

mod test {
    use super::*;

    use libsmt::logics::qf_abv;
    use libsmt::backends::smtlib2::SMTLib2;

    use crate::memory::seg_mem::SegMem;
    use crate::regstore::regfile::RuneRegFile;

    use r2api::structs::Endian;

    // #[test]
    fn testing_memory_my_dude() {
        let mut lreginfo = Default::default();
        let regstore = RuneRegFile::new(&mut lreginfo);

        let mut mem = SegMem::new(64, Endian::Big);
		let mut smt = SMTLib2::new(Some(qf_abv::QF_ABV));
		mem.init_memory(&mut smt);

        let _ctx = RuneContext::new(Some(0x9000), mem, regstore, smt);
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, collections::HashMap};

use criterion::{
    AxisScale, Bencher, Criterion, ParameterizedBenchmark, PlotConfiguration, Throughput,
};
use rand::{Rng, RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use serde_derive::{Deserialize, Serialize};

use exonum_crypto::{Hash, PublicKey, PUBLIC_KEY_LENGTH};
use exonum_merkledb::{
    BinaryValue, Database, Fork, IndexAccess, ListIndex, MapIndex, ProofListIndex, ProofMapIndex,
    TemporaryDB, UniqueHash,
};

const SEED: [u8; 16] = [100; 16];
const USERS_COUNT: usize = 10_000;
const SAMPLE_SIZE: usize = 10;

#[cfg(all(test, not(feature = "long_benchmarks")))]
const ITEM_COUNT: [BenchParams; 5] = [
    BenchParams {
        blocks_count: 1,
        txs_in_block_count: 10_000,
    },
    BenchParams {
        blocks_count: 10,
        txs_in_block_count: 1_000,
    },
    BenchParams {
        blocks_count: 100,
        txs_in_block_count: 100,
    },
    BenchParams {
        blocks_count: 1_000,
        txs_in_block_count: 10,
    },
    BenchParams {
        blocks_count: 10_000,
        txs_in_block_count: 1,
    },
];

#[cfg(all(test, feature = "long_benchmarks"))]
const ITEM_COUNT: [BenchParams; 6] = [
    BenchParams {
        blocks_count: 1,
        txs_in_block_count: 10_000,
    },
    BenchParams {
        blocks_count: 10,
        txs_in_block_count: 1_000,
    },
    BenchParams {
        blocks_count: 100,
        txs_in_block_count: 100,
    },
    BenchParams {
        blocks_count: 1_000,
        txs_in_block_count: 10,
    },
    BenchParams {
        blocks_count: 10_000,
        txs_in_block_count: 1,
    },
    BenchParams {
        blocks_count: 1_000,
        txs_in_block_count: 1_000,
    },
];

#[derive(Clone, Copy, Debug)]
struct BenchParams {
    blocks_count: usize,
    txs_in_block_count: usize,
}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Default)]
struct Wallet {
    incoming: u32,
    outgoing: u32,
    history_root: Hash,
}

impl BinaryValue for Wallet {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Wallet {}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
struct Transaction {
    sender: PublicKey,
    receiver: PublicKey,
    amount: u32,
}

impl BinaryValue for Transaction {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Transaction {}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Block {
    transactions: Vec<Transaction>,
}

impl BinaryValue for Block {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Block {}

struct Schema<T: IndexAccess>(T);

impl<T: IndexAccess> Schema<T> {
    fn new(index_access: T) -> Self {
        Self(index_access)
    }

    fn transactions(&self) -> MapIndex<T, Hash, Transaction> {
        MapIndex::new("transactions", self.0.clone())
    }

    fn blocks(&self) -> ListIndex<T, Hash> {
        ListIndex::new("blocks", self.0.clone())
    }

    fn wallets(&self) -> ProofMapIndex<T, PublicKey, Wallet> {
        ProofMapIndex::new("wallets", self.0.clone())
    }

    fn wallets_history(&self, owner: &PublicKey) -> ProofListIndex<T, Hash> {
        ProofListIndex::new_in_family("wallets.history", owner, self.0.clone())
    }
}

impl Schema<&Fork> {
    fn add_transaction_to_history(&self, owner: &PublicKey, tx_hash: Hash) -> Hash {
        let mut history = self.wallets_history(owner);
        history.push(tx_hash);
        history.list_hash()
    }
}

impl Transaction {
    fn execute(&self, fork: &Fork) {
        let tx_hash = self.hash();

        let schema = Schema::new(fork);
        schema.transactions().put(&self.hash(), *self);

        let mut owner_wallet = schema.wallets().get(&self.sender).unwrap_or_default();
        owner_wallet.outgoing += self.amount;
        owner_wallet.history_root = schema.add_transaction_to_history(&self.sender, tx_hash);
        schema.wallets().put(&self.sender, owner_wallet);

        let mut receiver_wallet = schema.wallets().get(&self.receiver).unwrap_or_default();
        receiver_wallet.incoming += self.amount;
        receiver_wallet.history_root = schema.add_transaction_to_history(&self.receiver, tx_hash);
        schema.wallets().put(&self.receiver, receiver_wallet);
    }
}

impl Block {
    fn execute(&self, db: &TemporaryDB) {
        let fork = db.fork();
        for transaction in &self.transactions {
            transaction.execute(&fork);
        }
        Schema::new(&fork).blocks().push(self.hash());
        db.merge(fork.into_patch()).unwrap();
    }
}

fn gen_random_blocks(blocks_count: usize, txs_count: usize, wallets_count: usize) -> Vec<Block> {
    let mut rng = XorShiftRng::from_seed(SEED);
    let users = (0..wallets_count)
        .into_iter()
        .map(|idx| {
            let mut base = [0; PUBLIC_KEY_LENGTH];
            rng.fill_bytes(&mut base);
            (idx, PublicKey::from_bytes(base.as_ref().into()).unwrap())
        })
        .collect::<HashMap<_, _>>();

    let get_random_user = |rng: &mut XorShiftRng| -> PublicKey {
        let id = rng.gen_range(0, wallets_count);
        *users.get(&id).unwrap()
    };

    (0..blocks_count)
        .into_iter()
        .map(move |_| {
            let transactions = (0..txs_count)
                .map(|_| Transaction {
                    sender: get_random_user(&mut rng),
                    receiver: get_random_user(&mut rng),
                    amount: rng.gen_range(0, 10),
                })
                .collect();
            Block { transactions }
        })
        .collect()
}

pub fn bench_transactions(c: &mut Criterion) {
    exonum_crypto::init();

    let item_counts = ITEM_COUNT.iter().cloned();
    c.bench(
        "transactions",
        ParameterizedBenchmark::new(
            "currency_like",
            move |b: &mut Bencher, params: &BenchParams| {
                let db = TemporaryDB::new();
                let blocks =
                    gen_random_blocks(params.blocks_count, params.txs_in_block_count, USERS_COUNT);
                b.iter(|| {
                    for block in &blocks {
                        block.execute(&db)
                    }
                })
            },
            item_counts,
        )
        .throughput(|&s| Throughput::Elements((s.txs_in_block_count * s.blocks_count) as u32))
        .plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic))
        .sample_size(SAMPLE_SIZE),
    );
}
<commit_msg>Add benchmark for different users count<commit_after>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, collections::HashMap};

use criterion::{
    AxisScale, Bencher, Criterion, ParameterizedBenchmark, PlotConfiguration, Throughput,
};
use rand::{Rng, RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use serde_derive::{Deserialize, Serialize};

use exonum_crypto::{Hash, PublicKey, PUBLIC_KEY_LENGTH};
use exonum_merkledb::{
    BinaryValue, Database, Fork, IndexAccess, ListIndex, MapIndex, ProofListIndex, ProofMapIndex,
    TemporaryDB, UniqueHash,
};

const SEED: [u8; 16] = [100; 16];
const SAMPLE_SIZE: usize = 10;

#[cfg(all(test, not(feature = "long_benchmarks")))]
const ITEM_COUNT: [BenchParams; 10] = [
    BenchParams {
        users: 10_000,
        blocks: 1,
        txs_in_block: 10_000,
    },
    BenchParams {
        users: 100,
        blocks: 1,
        txs_in_block: 10_000,
    },
    BenchParams {
        users: 10_000,
        blocks: 10,
        txs_in_block: 1_000,
    },
    BenchParams {
        users: 100,
        blocks: 10,
        txs_in_block: 1_000,
    },
    BenchParams {
        users: 10_000,
        blocks: 100,
        txs_in_block: 100,
    },
    BenchParams {
        users: 100,
        blocks: 100,
        txs_in_block: 100,
    },
    BenchParams {
        users: 10_000,
        blocks: 1_000,
        txs_in_block: 10,
    },
    BenchParams {
        users: 100,
        blocks: 1_000,
        txs_in_block: 10,
    },
    BenchParams {
        users: 10_000,
        blocks: 10_000,
        txs_in_block: 1,
    },
    BenchParams {
        users: 100,
        blocks: 10_000,
        txs_in_block: 1,
    },
];

#[cfg(all(test, feature = "long_benchmarks"))]
const ITEM_COUNT: [BenchParams; 6] = [
    BenchParams {
        users: 1_000,
        blocks: 10,
        txs_in_block: 10_000,
    },
    BenchParams {
        users: 1_000,
        blocks: 100,
        txs_in_block: 1_000,
    },
    BenchParams {
        users: 1_000,
        blocks: 1_000,
        txs_in_block: 100,
    },
    BenchParams {
        users: 1_000,
        blocks: 10_000,
        txs_in_block: 10,
    },
    BenchParams {
        users: 1_000,
        blocks: 100_000,
        txs_in_block: 1,
    },
    BenchParams {
        users: 1_000,
        blocks: 1_000_000,
        txs_in_block: 1_000,
    },
];

#[derive(Clone, Copy, Debug)]
struct BenchParams {
    users: usize,
    blocks: usize,
    txs_in_block: usize,
}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Default)]
struct Wallet {
    incoming: u32,
    outgoing: u32,
    history_root: Hash,
}

impl BinaryValue for Wallet {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Wallet {}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
struct Transaction {
    sender: PublicKey,
    receiver: PublicKey,
    amount: u32,
}

impl BinaryValue for Transaction {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Transaction {}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Block {
    transactions: Vec<Transaction>,
}

impl BinaryValue for Block {
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Block {}

struct Schema<T: IndexAccess>(T);

impl<T: IndexAccess> Schema<T> {
    fn new(index_access: T) -> Self {
        Self(index_access)
    }

    fn transactions(&self) -> MapIndex<T, Hash, Transaction> {
        MapIndex::new("transactions", self.0.clone())
    }

    fn blocks(&self) -> ListIndex<T, Hash> {
        ListIndex::new("blocks", self.0.clone())
    }

    fn wallets(&self) -> ProofMapIndex<T, PublicKey, Wallet> {
        ProofMapIndex::new("wallets", self.0.clone())
    }

    fn wallets_history(&self, owner: &PublicKey) -> ProofListIndex<T, Hash> {
        ProofListIndex::new_in_family("wallets.history", owner, self.0.clone())
    }
}

impl Schema<&Fork> {
    fn add_transaction_to_history(&self, owner: &PublicKey, tx_hash: Hash) -> Hash {
        let mut history = self.wallets_history(owner);
        history.push(tx_hash);
        history.list_hash()
    }
}

impl Transaction {
    fn execute(&self, fork: &Fork) {
        let tx_hash = self.hash();

        let schema = Schema::new(fork);
        schema.transactions().put(&self.hash(), *self);

        let mut owner_wallet = schema.wallets().get(&self.sender).unwrap_or_default();
        owner_wallet.outgoing += self.amount;
        owner_wallet.history_root = schema.add_transaction_to_history(&self.sender, tx_hash);
        schema.wallets().put(&self.sender, owner_wallet);

        let mut receiver_wallet = schema.wallets().get(&self.receiver).unwrap_or_default();
        receiver_wallet.incoming += self.amount;
        receiver_wallet.history_root = schema.add_transaction_to_history(&self.receiver, tx_hash);
        schema.wallets().put(&self.receiver, receiver_wallet);
    }
}

impl Block {
    fn execute(&self, db: &TemporaryDB) {
        let fork = db.fork();
        for transaction in &self.transactions {
            transaction.execute(&fork);
        }
        Schema::new(&fork).blocks().push(self.hash());
        db.merge(fork.into_patch()).unwrap();
    }
}

fn gen_random_blocks(blocks: usize, txs_count: usize, wallets_count: usize) -> Vec<Block> {
    let mut rng = XorShiftRng::from_seed(SEED);
    let users = (0..wallets_count)
        .into_iter()
        .map(|idx| {
            let mut base = [0; PUBLIC_KEY_LENGTH];
            rng.fill_bytes(&mut base);
            (idx, PublicKey::from_bytes(base.as_ref().into()).unwrap())
        })
        .collect::<HashMap<_, _>>();

    let get_random_user = |rng: &mut XorShiftRng| -> PublicKey {
        let id = rng.gen_range(0, wallets_count);
        *users.get(&id).unwrap()
    };

    (0..blocks)
        .into_iter()
        .map(move |_| {
            let transactions = (0..txs_count)
                .map(|_| Transaction {
                    sender: get_random_user(&mut rng),
                    receiver: get_random_user(&mut rng),
                    amount: rng.gen_range(0, 10),
                })
                .collect();
            Block { transactions }
        })
        .collect()
}

pub fn bench_transactions(c: &mut Criterion) {
    exonum_crypto::init();

    let item_counts = ITEM_COUNT.iter().cloned();
    c.bench(
        "transactions",
        ParameterizedBenchmark::new(
            "currency_like",
            move |b: &mut Bencher, params: &BenchParams| {
                let db = TemporaryDB::new();
                let blocks = gen_random_blocks(params.blocks, params.txs_in_block, params.users);
                b.iter(|| {
                    for block in &blocks {
                        block.execute(&db)
                    }
                })
            },
            item_counts,
        )
        .throughput(|&s| Throughput::Elements((s.txs_in_block * s.blocks) as u32))
        .plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic))
        .sample_size(SAMPLE_SIZE),
    );
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate serde_json;
extern crate tokio_core;
extern crate telegram_bot_raw;

#[cfg(feature = "curl_connector")]
extern crate curl;
#[cfg(feature = "curl_connector")]
extern crate tokio_curl;

#[cfg(feature = "hyper_connector")]
extern crate hyper;
#[cfg(feature = "hyper_connector")]
extern crate hyper_tls;

mod api;
mod errors;
mod future;
mod stream;

pub mod connector;
pub mod prelude;
pub mod types;

pub use self::api::Api;
pub use self::connector::*;
pub use self::errors::{Error, Result, ErrorKind};
pub use self::future::TelegramFuture;
pub use stream::UpdatesStream;
pub use prelude::*;
pub use types::*;
<commit_msg>docs: minor fix<commit_after>#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate serde_json;
extern crate tokio_core;
extern crate telegram_bot_raw;

#[cfg(feature = "curl_connector")]
extern crate curl;
#[cfg(feature = "curl_connector")]
extern crate tokio_curl;

#[cfg(feature = "hyper_connector")]
extern crate hyper;
#[cfg(feature = "hyper_connector")]
extern crate hyper_tls;

mod api;
mod errors;
mod future;
mod stream;

pub mod connector;
pub mod prelude;
pub mod types;

pub use self::api::Api;
pub use connector::*;
pub use self::errors::{Error, Result, ErrorKind};
pub use self::future::TelegramFuture;
pub use stream::UpdatesStream;
pub use prelude::*;
pub use types::*;
<|endoftext|>


<commit_before>extern crate pretty_env_logger;
#[macro_use] extern crate log;

mod one {
    pub fn deep() {
        trace!("one level deep!");
    }
}

fn main() {
    pretty_env_logger::init();

    self::one::deep();
    debug!("deboogging");
    info!("such information");
    warn!("o_O");
    error!("boom");
}
<commit_msg>add note to example to increase log level<commit_after>extern crate pretty_env_logger;
#[macro_use] extern crate log;

mod nested {
    pub fn deep() {
        trace!("one level deep!");
    }
}

fn main() {
    pretty_env_logger::init();

    if !log_enabled!(log::Level::Trace) {
        eprintln!("To see the full demo, try setting `RUST_LOG=log=trace`.");
        return;
    }

    self::nested::deep();
    debug!("deboogging");
    info!("such information");
    warn!("o_O");
    error!("boom");
}
<|endoftext|>


<commit_before>use crate::{error::{Error as HabError,
                    Result},
            hcore::fs::{am_i_root,
                        FS_ROOT_PATH},
            CTL_SECRET_ENVVAR};
use habitat_core::{env as henv,
                   origin::Origin};
use habitat_sup_client::SrvClient;
use std::{fs::{self,
               File},
          io::{self,
               Write},
          path::{Path,
                 PathBuf}};

const CLI_CONFIG_PATH_POSTFIX: &str = "hab/etc/cli.toml";

lazy_static::lazy_static! {
    pub static ref CLI_CONFIG_PATH: PathBuf = cli_config_path();

    /// A cached reading of the config file. This avoids the need to continually read from disk.
    /// However, it also means changes to the file will not be picked up after the program has
    /// started. Ideally, we would repopulate this struct on file change or on some configured
    /// interval.
    /// https://github.com/habitat-sh/habitat/issues/7243
    pub static ref CACHED: Config = load().unwrap_or_default();
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("reading '{}' failed, err: {0}", CLI_CONFIG_PATH.display())]
    File(#[from] io::Error),
    #[error("parsing '{}' failed, err: {0}", CLI_CONFIG_PATH.display())]
    Toml(#[from] toml::de::Error),
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct Config {
    pub auth_token: Option<String>,
    pub origin:     Option<Origin>,
    pub ctl_secret: Option<String>,
    pub bldr_url:   Option<String>,
}

impl Config {
    fn from_file<T: AsRef<Path>>(path: T) -> std::result::Result<Self, Error> {
        let raw = fs::read_to_string(path)?;
        Ok(toml::from_str(&raw)?)
    }
}

impl Default for Config {
    fn default() -> Self {
        Config { auth_token: None,
                 origin:     None,
                 ctl_secret: None,
                 bldr_url:   None, }
    }
}

pub fn load() -> std::result::Result<Config, Error> {
    if CLI_CONFIG_PATH.exists() {
        debug!("Loading CLI config from {}", CLI_CONFIG_PATH.display());
        Ok(Config::from_file(&*CLI_CONFIG_PATH)?)
    } else {
        debug!("No CLI config found, loading defaults");
        Ok(Config::default())
    }
}

pub fn save(config: &Config) -> Result<()> {
    let parent_path = match CLI_CONFIG_PATH.parent() {
        Some(p) => p,
        None => {
            return Err(HabError::FileNotFound(CLI_CONFIG_PATH.display().to_string()));
        }
    };
    fs::create_dir_all(&parent_path)?;
    let raw = toml::ser::to_string(config)?;
    debug!("Raw config toml:\n---\n{}\n---", &raw);
    let mut file = File::create(&*CLI_CONFIG_PATH)?;
    file.write_all(raw.as_bytes())?;
    Ok(())
}

/// Check if the HAB_CTL_SECRET env var. If not, check the CLI config to see if there is a ctl
/// secret set and return a copy of that value.
pub fn ctl_secret_key(config: &Config) -> Result<String> {
    match henv::var(CTL_SECRET_ENVVAR) {
        Ok(v) => Ok(v),
        Err(_) => {
            match config.ctl_secret {
                Some(ref v) => Ok(v.to_string()),
                None => SrvClient::read_secret_key().map_err(HabError::from),
            }
        }
    }
}

fn cli_config_path() -> PathBuf {
    if !am_i_root() {
        if let Some(home) = dirs::home_dir() {
            return home.join(format!(".{}", CLI_CONFIG_PATH_POSTFIX));
        }
    }
    PathBuf::from(&*FS_ROOT_PATH).join(CLI_CONFIG_PATH_POSTFIX)
}
<commit_msg>[Refactor] Cli config path always has a parent<commit_after>use crate::{error::{Error as HabError,
                    Result},
            hcore::fs::{am_i_root,
                        FS_ROOT_PATH},
            CTL_SECRET_ENVVAR};
use habitat_core::{env as henv,
                   origin::Origin};
use habitat_sup_client::SrvClient;
use std::{fs::{self,
               File},
          io::{self,
               Write},
          path::{Path,
                 PathBuf}};

const CLI_CONFIG_PATH_POSTFIX: &str = "hab/etc/cli.toml";

lazy_static::lazy_static! {
    pub static ref CLI_CONFIG_PATH: PathBuf = cli_config_path();
    pub static ref CLI_CONFIG_PATH_PARENT: &'static Path = CLI_CONFIG_PATH
                                                    .parent()
                                                    .expect("cli config path parent");

    /// A cached reading of the config file. This avoids the need to continually read from disk.
    /// However, it also means changes to the file will not be picked up after the program has
    /// started. Ideally, we would repopulate this struct on file change or on some configured
    /// interval.
    /// https://github.com/habitat-sh/habitat/issues/7243
    pub static ref CACHED: Config = load().unwrap_or_default();
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("reading '{}' failed, err: {0}", CLI_CONFIG_PATH.display())]
    File(#[from] io::Error),
    #[error("parsing '{}' failed, err: {0}", CLI_CONFIG_PATH.display())]
    Toml(#[from] toml::de::Error),
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct Config {
    pub auth_token: Option<String>,
    pub origin:     Option<Origin>,
    pub ctl_secret: Option<String>,
    pub bldr_url:   Option<String>,
}

impl Config {
    fn from_file<T: AsRef<Path>>(path: T) -> std::result::Result<Self, Error> {
        let raw = fs::read_to_string(path)?;
        Ok(toml::from_str(&raw)?)
    }
}

impl Default for Config {
    fn default() -> Self {
        Config { auth_token: None,
                 origin:     None,
                 ctl_secret: None,
                 bldr_url:   None, }
    }
}

pub fn load() -> std::result::Result<Config, Error> {
    if CLI_CONFIG_PATH.exists() {
        debug!("Loading CLI config from {}", CLI_CONFIG_PATH.display());
        Ok(Config::from_file(&*CLI_CONFIG_PATH)?)
    } else {
        debug!("No CLI config found, loading defaults");
        Ok(Config::default())
    }
}

pub fn save(config: &Config) -> Result<()> {
    fs::create_dir_all(&*CLI_CONFIG_PATH_PARENT)?;
    let raw = toml::ser::to_string(config)?;
    debug!("Raw config toml:\n---\n{}\n---", &raw);
    let mut file = File::create(&*CLI_CONFIG_PATH)?;
    file.write_all(raw.as_bytes())?;
    Ok(())
}

/// Check if the HAB_CTL_SECRET env var. If not, check the CLI config to see if there is a ctl
/// secret set and return a copy of that value.
pub fn ctl_secret_key(config: &Config) -> Result<String> {
    match henv::var(CTL_SECRET_ENVVAR) {
        Ok(v) => Ok(v),
        Err(_) => {
            match config.ctl_secret {
                Some(ref v) => Ok(v.to_string()),
                None => SrvClient::read_secret_key().map_err(HabError::from),
            }
        }
    }
}

fn cli_config_path() -> PathBuf {
    if !am_i_root() {
        if let Some(home) = dirs::home_dir() {
            return home.join(format!(".{}", CLI_CONFIG_PATH_POSTFIX));
        }
    }
    PathBuf::from(&*FS_ROOT_PATH).join(CLI_CONFIG_PATH_POSTFIX)
}
<|endoftext|>


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

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use task::spawn_named;
use task_state;

use libc::funcs::posix88::unistd::usleep;
use rand::{Rng, weak_rng, XorShiftRng};
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver};

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

fn next_power_of_two(mut v: u32) -> u32 {
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v += 1;
    v
}

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = next_power_of_two(self.other_deques.len() as u32) - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            //
            // FIXME(pcwalton): Can't use labeled break or continue cross-crate due to a Rust bug.
            loop {
                // FIXME(pcwalton): Nasty workaround for the lack of labeled break/continue
                // cross-crate.
                let mut work_unit = unsafe {
                    mem::uninitialized()
                };
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        let mut should_continue = true;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => {
                                            should_continue = false;
                                            break
                                        }
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                unsafe {
                                    usleep(back_off_sleep as u32);
                                }
                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }

                        if !should_continue {
                            break
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: *const QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'b>(&'b self) -> &'b QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: usize,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in 0..thread_count {
            for j in 0..thread_count {
                if i != j {
                    threads[i].other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", task_name, i+1, thread_count),
                move || {
                    task_state::initialize(state | task_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              &self.data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<commit_msg>Auto merge of #6504 - Ms2ger:workqueue-labeled-break, r=pcwalton<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use task::spawn_named;
use task_state;

use libc::funcs::posix88::unistd::usleep;
use rand::{Rng, weak_rng, XorShiftRng};
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver};

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

fn next_power_of_two(mut v: u32) -> u32 {
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v += 1;
    v
}

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = next_power_of_two(self.other_deques.len() as u32) - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            'outer: loop {
                let work_unit;
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => break 'outer,
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                unsafe {
                                    usleep(back_off_sleep as u32);
                                }
                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: *const QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'b>(&'b self) -> &'b QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: usize,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in 0..thread_count {
            for j in 0..thread_count {
                if i != j {
                    threads[i].other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", task_name, i+1, thread_count),
                move || {
                    task_state::initialize(state | task_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              &self.data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<|endoftext|>


<commit_before>#[link(name="base64", vers="1.0.0", author="Jordy Dickinson")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern mod extra;

use std::char;
use std::io::{File, stdin, stdout};
use std::os;
use std::str;

use extra::base64;
use extra::base64::{FromBase64, ToBase64};

fn main() {
    let mut conf = Conf::new(os::args());

    match conf.mode {
        Decode  => decode(&mut conf),
        Encode  => encode(&mut conf),
        Help    => help(&conf),
        Version => version()
    }
}

fn decode(conf: &mut Conf) {
    let mut to_decode = str::from_utf8_owned(conf.input_file.read_to_end());

    to_decode = to_decode.replace("\n", "");

    if conf.ignore_garbage {
        let standard_chars =
            bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
            "abcdefghijklmnopqrstuvwxyz",
            "0123456789+/").map(|b| char::from_u32(*b as u32).unwrap());

        to_decode = to_decode
            .trim_chars(&|c| !standard_chars.contains(&c))
            .to_owned();
    }

    match to_decode.from_base64() {
        Ok(bytes) => {
            let mut out = stdout();

            out.write(bytes);
            out.flush();
        }
        Err(s) => {
            error!("error: {:s}", s);
            fail!()
        }
    }
}

fn encode(conf: &mut Conf) {
    let b64_conf = base64::Config {
        char_set: base64::Standard,
        pad: true,
        line_length: match conf.line_wrap {
            0 => None,
            _ => Some(conf.line_wrap)
        }
    };
    let to_encode = conf.input_file.read_to_end();
    let mut encoded = to_encode.to_base64(b64_conf);

    // To my knowledge, RFC 3548 does not specify which line endings to use. It
    // seems that rust's base64 algorithm uses CRLF as prescribed by RFC 2045.
    // However, since GNU base64 outputs only LF (presumably because that is
    // the standard UNIX line ending), we strip CRs from the output to maintain
    // compatibility.
    encoded = encoded.replace("\r", "");

    println(encoded);
}

fn help(conf: &Conf) {
    println!("Usage: {:s} [OPTION]... [FILE]", conf.progname);
    println("");
    println(conf.usage);

    let msg = ~"With no FILE, or when FILE is -, read standard input.\n\n\
        The data are encoded as described for the base64 alphabet in RFC \
        3548. When\ndecoding, the input may contain newlines in addition \
        to the bytes of the formal\nbase64 alphabet. Use --ignore-garbage \
        to attempt to recover from any other\nnon-alphabet bytes in the \
        encoded stream.";

    println(msg);
}

fn version() {
    println("base64 1.0.0");
}

struct Conf {
    progname: ~str,
    usage: ~str,
    mode: Mode,
    ignore_garbage: bool,
    line_wrap: uint,
    input_file: ~Reader
}

impl Conf {
    fn new(args: &[~str]) -> Conf {
        // The use statement is here rather than at the top of the file so that
        // the reader is made directly aware that we're using getopts::groups,
        // and not just getopts. Also some names are somewhat vague taken out
        // of context (i.e., "usage").
        use extra::getopts::groups::{
            getopts,
            optflag,
            optopt,
            usage
        };

        let opts = ~[
            optflag("d", "decode", "decode data"),
            optflag("i", "ignore-garbage",
            "when decoding, ignore non-alphabetic characters"),
            optopt("w", "wrap",
            "wrap encoded lines after COLS character (default 76, 0 to \
            disable wrapping)", "COLS"),
            optflag("h", "help", "display this help text and exit"),
            optflag("V", "version", "output version information and exit")
                ];
        let matches = match getopts(args.tail(), opts) {
            Ok(m) => m,
            Err(e) => {
                error!("error: {:s}", e.to_err_msg());
                fail!()
            }
        };

        Conf {
            progname: args[0].clone(),
            usage: usage("Base64 encode or decode FILE, or standard input, to \
                         standard output.", opts),
            mode: if matches.opt_present("help") {
                Help
            } else if matches.opt_present("version") {
                Version
            } else if matches.opt_present("decode") {
                Decode
            } else {
                Encode
            },
            ignore_garbage: matches.opt_present("ignore-garbage"),
            line_wrap: match matches.opt_str("wrap") {
                Some(s) => match from_str(s) {
                    Some(s) => s,
                    None => {
                        error!("error: {:s}", "Argument to option 'wrap' \
                               improperly formatted.");
                        fail!()
                    }
                },
                None => 76
            },
            input_file: if matches.free.is_empty()
                            || matches.free[0] == ~"-" {
                ~stdin() as ~Reader
            } else {
                let path = Path::new(matches.free[0]);
                ~File::open(&path) as ~Reader
            }
        }
    }
}

enum Mode {
    Decode,
    Encode,
    Help,
    Version
}

<commit_msg>link -> crate_id; link is deprecated<commit_after>#[crate_id = "base64#1.0.0"];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern mod extra;

use std::char;
use std::io::{File, stdin, stdout};
use std::os;
use std::str;

use extra::base64;
use extra::base64::{FromBase64, ToBase64};

fn main() {
    let mut conf = Conf::new(os::args());

    match conf.mode {
        Decode  => decode(&mut conf),
        Encode  => encode(&mut conf),
        Help    => help(&conf),
        Version => version()
    }
}

fn decode(conf: &mut Conf) {
    let mut to_decode = str::from_utf8_owned(conf.input_file.read_to_end());

    to_decode = to_decode.replace("\n", "");

    if conf.ignore_garbage {
        let standard_chars =
            bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
            "abcdefghijklmnopqrstuvwxyz",
            "0123456789+/").map(|b| char::from_u32(*b as u32).unwrap());

        to_decode = to_decode
            .trim_chars(&|c| !standard_chars.contains(&c))
            .to_owned();
    }

    match to_decode.from_base64() {
        Ok(bytes) => {
            let mut out = stdout();

            out.write(bytes);
            out.flush();
        }
        Err(s) => {
            error!("error: {:s}", s);
            fail!()
        }
    }
}

fn encode(conf: &mut Conf) {
    let b64_conf = base64::Config {
        char_set: base64::Standard,
        pad: true,
        line_length: match conf.line_wrap {
            0 => None,
            _ => Some(conf.line_wrap)
        }
    };
    let to_encode = conf.input_file.read_to_end();
    let mut encoded = to_encode.to_base64(b64_conf);

    // To my knowledge, RFC 3548 does not specify which line endings to use. It
    // seems that rust's base64 algorithm uses CRLF as prescribed by RFC 2045.
    // However, since GNU base64 outputs only LF (presumably because that is
    // the standard UNIX line ending), we strip CRs from the output to maintain
    // compatibility.
    encoded = encoded.replace("\r", "");

    println(encoded);
}

fn help(conf: &Conf) {
    println!("Usage: {:s} [OPTION]... [FILE]", conf.progname);
    println("");
    println(conf.usage);

    let msg = ~"With no FILE, or when FILE is -, read standard input.\n\n\
        The data are encoded as described for the base64 alphabet in RFC \
        3548. When\ndecoding, the input may contain newlines in addition \
        to the bytes of the formal\nbase64 alphabet. Use --ignore-garbage \
        to attempt to recover from any other\nnon-alphabet bytes in the \
        encoded stream.";

    println(msg);
}

fn version() {
    println("base64 1.0.0");
}

struct Conf {
    progname: ~str,
    usage: ~str,
    mode: Mode,
    ignore_garbage: bool,
    line_wrap: uint,
    input_file: ~Reader
}

impl Conf {
    fn new(args: &[~str]) -> Conf {
        // The use statement is here rather than at the top of the file so that
        // the reader is made directly aware that we're using getopts::groups,
        // and not just getopts. Also some names are somewhat vague taken out
        // of context (i.e., "usage").
        use extra::getopts::groups::{
            getopts,
            optflag,
            optopt,
            usage
        };

        let opts = ~[
            optflag("d", "decode", "decode data"),
            optflag("i", "ignore-garbage",
            "when decoding, ignore non-alphabetic characters"),
            optopt("w", "wrap",
            "wrap encoded lines after COLS character (default 76, 0 to \
            disable wrapping)", "COLS"),
            optflag("h", "help", "display this help text and exit"),
            optflag("V", "version", "output version information and exit")
                ];
        let matches = match getopts(args.tail(), opts) {
            Ok(m) => m,
            Err(e) => {
                error!("error: {:s}", e.to_err_msg());
                fail!()
            }
        };

        Conf {
            progname: args[0].clone(),
            usage: usage("Base64 encode or decode FILE, or standard input, to \
                         standard output.", opts),
            mode: if matches.opt_present("help") {
                Help
            } else if matches.opt_present("version") {
                Version
            } else if matches.opt_present("decode") {
                Decode
            } else {
                Encode
            },
            ignore_garbage: matches.opt_present("ignore-garbage"),
            line_wrap: match matches.opt_str("wrap") {
                Some(s) => match from_str(s) {
                    Some(s) => s,
                    None => {
                        error!("error: {:s}", "Argument to option 'wrap' \
                               improperly formatted.");
                        fail!()
                    }
                },
                None => 76
            },
            input_file: if matches.free.is_empty()
                            || matches.free[0] == ~"-" {
                ~stdin() as ~Reader
            } else {
                let path = Path::new(matches.free[0]);
                ~File::open(&path) as ~Reader
            }
        }
    }
}

enum Mode {
    Decode,
    Encode,
    Help,
    Version
}

<|endoftext|>