<commit_before>// vim: tw=80
#![cfg_attr(feature = "nightly", feature(specialization))]

use cfg_if::cfg_if;
use downcast::*;
use std::{
    any,
    collections::hash_map::HashMap,
    mem,
    ops::{DerefMut, Range},
    sync::{
        Arc,
        Mutex,
        atomic::{AtomicUsize, Ordering}
    },
    thread
};

pub use predicates::prelude::*;

trait AnyExpectation : Any + Send {}
downcast!(AnyExpectation);

trait ReturnDefault<O> {
    fn return_default() -> O;
}

/// Return functions for expectations
enum Rfunc<I, O> {
    Default,
    // Indicates that a `return_once` expectation has already returned
    Expired,
    Mut(Box<dyn FnMut(I) -> O + Send>),
    // Should be Box<dyn FnOnce> once that feature is stabilized
    // https://github.com/rust-lang/rust/issues/28796
    Once(Box<dyn FnMut(I) -> O + Send>),
}

// TODO: change this to "impl FnMut" once unboxed_closures are stable
// https://github.com/rust-lang/rust/issues/29625
impl<I, O>  Rfunc<I, O> {
    fn call_mut(&mut self, args: I) -> O {
        match self {
            Rfunc::Default => {
                Self::return_default()
            },
            Rfunc::Expired => {
                panic!("Called a method twice that was expected only once")
            },
            Rfunc::Mut(f) => {
                f(args)
            },
            Rfunc::Once(_) => {
                let fo = mem::replace(self, Rfunc::Expired);
                if let Rfunc::Once(mut f) = fo {
                    f(args)
                } else {
                    unreachable!()
                }
            },
        }
    }
}

impl<I, O> Default for Rfunc<I, O> {
    fn default() -> Self {
        Rfunc::Default
    }
}

cfg_if! {
    if #[cfg(feature = "nightly")] {
        impl<I, O> ReturnDefault<O> for Rfunc<I, O> {
            default fn return_default() -> O {
                panic!("Can only return default values for types that impl std::Default");
            }
        }

        impl<I, O: Default> ReturnDefault<O> for Rfunc<I, O> {
            fn return_default() -> O {
                O::default()
            }
        }
    } else {
        impl<I, O> ReturnDefault<O> for Rfunc<I, O> {
            fn return_default() -> O {
                panic!("Returning default values requires the \"nightly\" feature");
            }
        }
    }
}

struct Matcher<I>(Box<dyn Predicate<I> + Send>);

impl<I> Matcher<I> {
    fn verify(&self, i: &I) {
        if let Some(case) = self.0.find_case(false, &i) {
            let c = &case as &predicates_tree::CaseTreeExt;
            panic!("Expectation didn't match arguments:\n{}", c.tree());
        }
    }
}

impl<I> Default for Matcher<I> {
    fn default() -> Self {
        Matcher(Box::new(predicate::always()))
    }
}

struct Times{
    /// How many times has the expectation already been called?
    count: AtomicUsize,
    range: Range<usize>
}

impl Times {
    fn call(&self) {
        let count = self.count.fetch_add(1, Ordering::Relaxed) + 1;
        if count >= self.range.end {
            if self.range.end == 0 {
                panic!("Expectation should not have been called");
            } else {
                let lim = self.range.end - 1;
                panic!("Expectation called more than {} times", lim);
            }
        }
    }

    fn any(&mut self) {
        self.range = 0..usize::max_value();
    }

    /// Is it required that this expectation be called an exact number of times,
    /// or may it be satisfied by a range of call counts?
    fn is_exact(&self) -> bool {
        (self.range.end - self.range.start) == 1
    }

    fn n(&mut self, n: usize) {
        self.range = n..(n+1);
    }

    fn never(&mut self) {
        self.range = 0..0;
    }

    fn range(&mut self, range: Range<usize>) {
        self.range = range;
    }

    /// Has this expectation already been called the minimum required number of
    /// times?
    fn is_satisfied(&self) -> bool {
        self.count.load(Ordering::Relaxed) >= self.range.start
    }
}

impl Default for Times {
    fn default() -> Self {
        // By default, allow any number of calls
        let count = AtomicUsize::default();
        let range = 0..usize::max_value();
        Times{count, range}
    }
}

impl Drop for Times {
    fn drop(&mut self) {
        let count = self.count.load(Ordering::Relaxed);
        if !thread::panicking() && (count < self.range.start) {
            panic!("Expectation called fewer than {} times", self.range.start);
        }
    }
}

impl<I, O> Default for Expectation<I, O> {
    fn default() -> Self {
        Expectation::new()
    }
}

struct ExpectationCommon<I> {
    matcher: Matcher<I>,
    seq_handle: Option<SeqHandle>,
    times: Times
}

impl<I> ExpectationCommon<I> {
    pub fn call(&self, i: &I) {
        self.matcher.verify(i);
        self.times.call();
        self.verify_sequence();
        if self.times.is_satisfied() {
            self.satisfy_sequence()
        }
    }

    pub fn in_sequence(&mut self, seq: &mut Sequence) -> &mut Self {
        assert!(self.times.is_exact(),
            "Only Expectations with an exact call count have sequences");
        self.seq_handle = Some(seq.next());
        self
    }

    /// Forbid this expectation from ever being called
    pub fn never(&mut self) {
        self.times.never();
    }

    fn satisfy_sequence(&self) {
        if let Some(handle) = &self.seq_handle {
            handle.satisfy()
        }
    }

    /// Require this expectation to be called exactly `n` times.
    pub fn times(&mut self, n: usize) {
        self.times.n(n);
    }

    /// Allow this expectation to be called any number of times
    pub fn times_any(&mut self) {
        self.times.any();
    }

    /// Allow this expectation to be called any number of times within a given
    /// range
    pub fn times_range(&mut self, range: Range<usize>) {
        self.times.range(range);
    }

    fn verify_sequence(&self) {
        if let Some(handle) = &self.seq_handle {
            handle.verify()
        }
    }

    pub fn with<P>(&mut self, p: P)
        where P: Predicate<I> + Send + 'static
    {
        self.matcher = Matcher(Box::new(p));
    }
}

impl<I> Default for ExpectationCommon<I> {
    fn default() -> Self {
        ExpectationCommon {
            times: Times::default(),
            matcher: Matcher::default(),
            seq_handle: None,
        }
    }
}

/// Add common methods to Expectation types.  Must be called from within an
/// impl<I, O> {} block
macro_rules! expectation_common {
    ($common: ident, $klass:ident) => {
        pub fn in_sequence(&mut self, seq: &mut Sequence) -> &mut Self {
            self.$common.in_sequence(seq);
            self
        }

        /// Forbid this expectation from ever being called
        pub fn never(&mut self) -> &mut Self {
            self.$common.never();
            self
        }

        /// Require this expectation to be called exactly `n` times.
        pub fn times(&mut self, n: usize) -> &mut Self {
            self.$common.times(n);
            self
        }

        /// Allow this expectation to be called any number of times
        pub fn times_any(&mut self) -> &mut Self {
            self.$common.times_any();
            self
        }

        /// Allow this expectation to be called any number of times within a
        /// given range
        pub fn times_range(&mut self, range: Range<usize>) -> &mut Self {
            self.$common.times_range(range);
            self
        }

        pub fn with<P>(&mut self, p: P) -> &mut Self
            where P: Predicate<I> + Send + 'static
        {
            self.$common.with(p);
            self
        }
    }
}

/// Expectation type for methods that take return a `'static` type.
pub struct Expectation<I, O> {
    common: ExpectationCommon<I>,
    rfunc: Mutex<Rfunc<I, O>>,
}

impl<I, O> Expectation<I, O> {
    pub fn call(&self, i: I) -> O {
        self.common.call(&i);
        self.rfunc.lock().unwrap()
            .call_mut(i)
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        let rfunc = Mutex::new(Rfunc::Default);
        Expectation{common, rfunc}
    }

    pub fn returning<F>(&mut self, f: F) -> &mut Self
        where F: FnMut(I) -> O + Send + 'static
    {
        {
            let mut guard = self.rfunc.lock().unwrap();
            mem::replace(guard.deref_mut(), Rfunc::Mut(Box::new(f)));
        }
        self
    }

    pub fn return_once<F>(&mut self, f: F) -> &mut Self
        where F: FnOnce(I) -> O + Send + 'static
    {
        let mut fopt = Some(f);
        let fmut = move |i| {
            if let Some(f) = fopt.take() {
                f(i)
            } else {
                panic!("Called a method twice that was expected only once")
            }
        };
        {
            let mut guard = self.rfunc.lock().unwrap();
            mem::replace(guard.deref_mut(), Rfunc::Once(Box::new(fmut)));
        }
        self
    }

    expectation_common!{common, Expectation}
}

impl<I: 'static, O: 'static> AnyExpectation for Expectation<I, O> {}

/// Expectation type for methods that take a `&self` argument and return a
/// reference with the same lifetime as `self`.
pub struct RefExpectation<I, O> {
    common: ExpectationCommon<I>,
    result: Option<O>,
    phantom: std::marker::PhantomData<I> ,
}

impl<I, O> RefExpectation<I, O> {
    pub fn call(&self, i: I) -> &O {
        self.common.call(&i);
        &self.result.as_ref()
            .expect("Must set return value with RefExpectation::return_const")
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        let phantom = std::marker::PhantomData;
        RefExpectation{common, result: None, phantom}
    }

    pub fn return_const(&mut self, o: O) -> &mut Self {
        self.result = Some(o);
        self
    }

    expectation_common!{common, RefExpectation}
}

impl<I, O> Default for RefExpectation<I, O> {
    fn default() -> Self {
        RefExpectation::new()
    }
}

impl<I, O> AnyExpectation for RefExpectation<I, O>
    where I: Send + 'static, O: Send + 'static
{}

/// Expectation type for methods that take a `&mut self` argument and return a
/// mutable or immutable reference with the same lifetime as `self`.
pub struct RefMutExpectation<I, O> {
    common: ExpectationCommon<I>,
    result: Option<O>,
    rfunc: Option<Box<dyn FnMut(I) -> O + Send>>,
}

impl<I, O> RefMutExpectation<I, O> {
    pub fn call_mut(&mut self, i: I) -> &mut O {
        self.common.call(&i);
        if let Some(ref mut f) = self.rfunc {
            self.result = Some(f(i));
        }
        self.result.as_mut().expect("Must first set return function with RefMutExpectation::returning or return_var")
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        RefMutExpectation{common, result: None, rfunc: None}
    }

    /// Convenience method that can be used to supply a return value for a
    /// `RefMutExpectation`.
    pub fn return_var(&mut self, o: O) -> &mut Self
    {
        self.result = Some(o);
        self
    }

    /// Supply a closure that the `RefMutExpectation` will use to create its
    /// return value.
    pub fn returning<F>(&mut self, f: F) -> &mut Self
        where F: FnMut(I) -> O + Send + 'static
    {
        mem::replace(&mut self.rfunc, Some(Box::new(f)));
        self
    }

    expectation_common!{common, RefMutExpectation}
}

impl<I, O> Default for RefMutExpectation<I, O> {
    fn default() -> Self {
        RefMutExpectation::new()
    }
}

impl<I, O> AnyExpectation for RefMutExpectation<I, O>
    where I: 'static, O: Send + 'static
{}

/// Non-generic keys to `GenericExpectation` internal storage
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct Key(any::TypeId);

impl Key {
    fn new<I: 'static, O: 'static>() -> Self {
        Key(any::TypeId::of::<(I, O)>())
    }
}

#[derive(Default)]
pub struct GenericExpectation {
    store: HashMap<Key, Box<dyn AnyExpectation>>
}

impl GenericExpectation {
    pub fn expect<'e, I, O>(&'e mut self) -> &'e mut Expectation<I, O>
        where I: 'static, O: 'static
    {
        let key = Key::new::<I, O>();
        let e = Box::new(Expectation::<I, O>::new());
        self.store.insert(key.clone(), e);
        self.store.get_mut(&key).unwrap()
            .downcast_mut()
            .unwrap()
    }

    // TODO: add a "called_nonstatic" method that can be used with types that
    // aren't 'static, and uses a different method to generate the key.
    pub fn call<I: 'static, O: 'static>(&self, args: I) -> O {
        let key = Key::new::<I, O>();
        let e: &Expectation<I, O> = self.store.get(&key)
            .expect("No matching expectation found")
            .downcast_ref()
            .unwrap();
        e.call(args)
    }
}

struct SeqHandle {
    inner: Arc<SeqInner>,
    seq: usize
}

impl SeqHandle {
    /// Tell the Sequence that this expectation has been fully satisfied
    fn satisfy(&self) {
        self.inner.satisfy(self.seq);
    }

    /// Verify that this handle was called in the correct order
    fn verify(&self) {
        self.inner.verify(self.seq);
    }
}

#[derive(Default)]
pub struct SeqInner {
    satisfaction_level: AtomicUsize,
}

impl SeqInner {
    /// Record the call identified by `seq` as fully satisfied.
    fn satisfy(&self, seq: usize) {
        let old_sl = self.satisfaction_level.fetch_add(1, Ordering::Relaxed);
        assert_eq!(old_sl, seq, "Method sequence violation.  Was an already-satisfied method called another time?");
    }

    /// Verify that the call identified by `seq` was called in the correct order
    fn verify(&self, seq: usize) {
        assert_eq!(seq, self.satisfaction_level.load(Ordering::Relaxed),
            "Method sequence violation")
    }
}

#[derive(Default)]
pub struct Sequence {
    inner: Arc<SeqInner>,
    next_seq: usize,
}

impl Sequence {
    pub fn new() -> Self {
        Self::default()
    }

    fn next(&mut self) -> SeqHandle {
        let handle = SeqHandle{inner: self.inner.clone(), seq: self.next_seq};
        self.next_seq += 1;
        handle
    }
}
<commit_msg>Remove an unnecessary PhantomData from RefExpectation<commit_after>// vim: tw=80
#![cfg_attr(feature = "nightly", feature(specialization))]

use cfg_if::cfg_if;
use downcast::*;
use std::{
    any,
    collections::hash_map::HashMap,
    mem,
    ops::{DerefMut, Range},
    sync::{
        Arc,
        Mutex,
        atomic::{AtomicUsize, Ordering}
    },
    thread
};

pub use predicates::prelude::*;

trait AnyExpectation : Any + Send {}
downcast!(AnyExpectation);

trait ReturnDefault<O> {
    fn return_default() -> O;
}

/// Return functions for expectations
enum Rfunc<I, O> {
    Default,
    // Indicates that a `return_once` expectation has already returned
    Expired,
    Mut(Box<dyn FnMut(I) -> O + Send>),
    // Should be Box<dyn FnOnce> once that feature is stabilized
    // https://github.com/rust-lang/rust/issues/28796
    Once(Box<dyn FnMut(I) -> O + Send>),
}

// TODO: change this to "impl FnMut" once unboxed_closures are stable
// https://github.com/rust-lang/rust/issues/29625
impl<I, O>  Rfunc<I, O> {
    fn call_mut(&mut self, args: I) -> O {
        match self {
            Rfunc::Default => {
                Self::return_default()
            },
            Rfunc::Expired => {
                panic!("Called a method twice that was expected only once")
            },
            Rfunc::Mut(f) => {
                f(args)
            },
            Rfunc::Once(_) => {
                let fo = mem::replace(self, Rfunc::Expired);
                if let Rfunc::Once(mut f) = fo {
                    f(args)
                } else {
                    unreachable!()
                }
            },
        }
    }
}

impl<I, O> Default for Rfunc<I, O> {
    fn default() -> Self {
        Rfunc::Default
    }
}

cfg_if! {
    if #[cfg(feature = "nightly")] {
        impl<I, O> ReturnDefault<O> for Rfunc<I, O> {
            default fn return_default() -> O {
                panic!("Can only return default values for types that impl std::Default");
            }
        }

        impl<I, O: Default> ReturnDefault<O> for Rfunc<I, O> {
            fn return_default() -> O {
                O::default()
            }
        }
    } else {
        impl<I, O> ReturnDefault<O> for Rfunc<I, O> {
            fn return_default() -> O {
                panic!("Returning default values requires the \"nightly\" feature");
            }
        }
    }
}

struct Matcher<I>(Box<dyn Predicate<I> + Send>);

impl<I> Matcher<I> {
    fn verify(&self, i: &I) {
        if let Some(case) = self.0.find_case(false, &i) {
            let c = &case as &predicates_tree::CaseTreeExt;
            panic!("Expectation didn't match arguments:\n{}", c.tree());
        }
    }
}

impl<I> Default for Matcher<I> {
    fn default() -> Self {
        Matcher(Box::new(predicate::always()))
    }
}

struct Times{
    /// How many times has the expectation already been called?
    count: AtomicUsize,
    range: Range<usize>
}

impl Times {
    fn call(&self) {
        let count = self.count.fetch_add(1, Ordering::Relaxed) + 1;
        if count >= self.range.end {
            if self.range.end == 0 {
                panic!("Expectation should not have been called");
            } else {
                let lim = self.range.end - 1;
                panic!("Expectation called more than {} times", lim);
            }
        }
    }

    fn any(&mut self) {
        self.range = 0..usize::max_value();
    }

    /// Is it required that this expectation be called an exact number of times,
    /// or may it be satisfied by a range of call counts?
    fn is_exact(&self) -> bool {
        (self.range.end - self.range.start) == 1
    }

    fn n(&mut self, n: usize) {
        self.range = n..(n+1);
    }

    fn never(&mut self) {
        self.range = 0..0;
    }

    fn range(&mut self, range: Range<usize>) {
        self.range = range;
    }

    /// Has this expectation already been called the minimum required number of
    /// times?
    fn is_satisfied(&self) -> bool {
        self.count.load(Ordering::Relaxed) >= self.range.start
    }
}

impl Default for Times {
    fn default() -> Self {
        // By default, allow any number of calls
        let count = AtomicUsize::default();
        let range = 0..usize::max_value();
        Times{count, range}
    }
}

impl Drop for Times {
    fn drop(&mut self) {
        let count = self.count.load(Ordering::Relaxed);
        if !thread::panicking() && (count < self.range.start) {
            panic!("Expectation called fewer than {} times", self.range.start);
        }
    }
}

impl<I, O> Default for Expectation<I, O> {
    fn default() -> Self {
        Expectation::new()
    }
}

struct ExpectationCommon<I> {
    matcher: Matcher<I>,
    seq_handle: Option<SeqHandle>,
    times: Times
}

impl<I> ExpectationCommon<I> {
    pub fn call(&self, i: &I) {
        self.matcher.verify(i);
        self.times.call();
        self.verify_sequence();
        if self.times.is_satisfied() {
            self.satisfy_sequence()
        }
    }

    pub fn in_sequence(&mut self, seq: &mut Sequence) -> &mut Self {
        assert!(self.times.is_exact(),
            "Only Expectations with an exact call count have sequences");
        self.seq_handle = Some(seq.next());
        self
    }

    /// Forbid this expectation from ever being called
    pub fn never(&mut self) {
        self.times.never();
    }

    fn satisfy_sequence(&self) {
        if let Some(handle) = &self.seq_handle {
            handle.satisfy()
        }
    }

    /// Require this expectation to be called exactly `n` times.
    pub fn times(&mut self, n: usize) {
        self.times.n(n);
    }

    /// Allow this expectation to be called any number of times
    pub fn times_any(&mut self) {
        self.times.any();
    }

    /// Allow this expectation to be called any number of times within a given
    /// range
    pub fn times_range(&mut self, range: Range<usize>) {
        self.times.range(range);
    }

    fn verify_sequence(&self) {
        if let Some(handle) = &self.seq_handle {
            handle.verify()
        }
    }

    pub fn with<P>(&mut self, p: P)
        where P: Predicate<I> + Send + 'static
    {
        self.matcher = Matcher(Box::new(p));
    }
}

impl<I> Default for ExpectationCommon<I> {
    fn default() -> Self {
        ExpectationCommon {
            times: Times::default(),
            matcher: Matcher::default(),
            seq_handle: None,
        }
    }
}

/// Add common methods to Expectation types.  Must be called from within an
/// impl<I, O> {} block
macro_rules! expectation_common {
    ($common: ident, $klass:ident) => {
        pub fn in_sequence(&mut self, seq: &mut Sequence) -> &mut Self {
            self.$common.in_sequence(seq);
            self
        }

        /// Forbid this expectation from ever being called
        pub fn never(&mut self) -> &mut Self {
            self.$common.never();
            self
        }

        /// Require this expectation to be called exactly `n` times.
        pub fn times(&mut self, n: usize) -> &mut Self {
            self.$common.times(n);
            self
        }

        /// Allow this expectation to be called any number of times
        pub fn times_any(&mut self) -> &mut Self {
            self.$common.times_any();
            self
        }

        /// Allow this expectation to be called any number of times within a
        /// given range
        pub fn times_range(&mut self, range: Range<usize>) -> &mut Self {
            self.$common.times_range(range);
            self
        }

        pub fn with<P>(&mut self, p: P) -> &mut Self
            where P: Predicate<I> + Send + 'static
        {
            self.$common.with(p);
            self
        }
    }
}

/// Expectation type for methods that take return a `'static` type.
pub struct Expectation<I, O> {
    common: ExpectationCommon<I>,
    rfunc: Mutex<Rfunc<I, O>>,
}

impl<I, O> Expectation<I, O> {
    pub fn call(&self, i: I) -> O {
        self.common.call(&i);
        self.rfunc.lock().unwrap()
            .call_mut(i)
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        let rfunc = Mutex::new(Rfunc::Default);
        Expectation{common, rfunc}
    }

    pub fn returning<F>(&mut self, f: F) -> &mut Self
        where F: FnMut(I) -> O + Send + 'static
    {
        {
            let mut guard = self.rfunc.lock().unwrap();
            mem::replace(guard.deref_mut(), Rfunc::Mut(Box::new(f)));
        }
        self
    }

    pub fn return_once<F>(&mut self, f: F) -> &mut Self
        where F: FnOnce(I) -> O + Send + 'static
    {
        let mut fopt = Some(f);
        let fmut = move |i| {
            if let Some(f) = fopt.take() {
                f(i)
            } else {
                panic!("Called a method twice that was expected only once")
            }
        };
        {
            let mut guard = self.rfunc.lock().unwrap();
            mem::replace(guard.deref_mut(), Rfunc::Once(Box::new(fmut)));
        }
        self
    }

    expectation_common!{common, Expectation}
}

impl<I: 'static, O: 'static> AnyExpectation for Expectation<I, O> {}

/// Expectation type for methods that take a `&self` argument and return a
/// reference with the same lifetime as `self`.
pub struct RefExpectation<I, O> {
    common: ExpectationCommon<I>,
    result: Option<O>,
}

impl<I, O> RefExpectation<I, O> {
    pub fn call(&self, i: I) -> &O {
        self.common.call(&i);
        &self.result.as_ref()
            .expect("Must set return value with RefExpectation::return_const")
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        RefExpectation{common, result: None}
    }

    pub fn return_const(&mut self, o: O) -> &mut Self {
        self.result = Some(o);
        self
    }

    expectation_common!{common, RefExpectation}
}

impl<I, O> Default for RefExpectation<I, O> {
    fn default() -> Self {
        RefExpectation::new()
    }
}

impl<I, O> AnyExpectation for RefExpectation<I, O>
    where I: Send + 'static, O: Send + 'static
{}

/// Expectation type for methods that take a `&mut self` argument and return a
/// mutable or immutable reference with the same lifetime as `self`.
pub struct RefMutExpectation<I, O> {
    common: ExpectationCommon<I>,
    result: Option<O>,
    rfunc: Option<Box<dyn FnMut(I) -> O + Send>>,
}

impl<I, O> RefMutExpectation<I, O> {
    pub fn call_mut(&mut self, i: I) -> &mut O {
        self.common.call(&i);
        if let Some(ref mut f) = self.rfunc {
            self.result = Some(f(i));
        }
        self.result.as_mut().expect("Must first set return function with RefMutExpectation::returning or return_var")
    }

    pub fn new() -> Self {
        let common = ExpectationCommon::default();
        RefMutExpectation{common, result: None, rfunc: None}
    }

    /// Convenience method that can be used to supply a return value for a
    /// `RefMutExpectation`.
    pub fn return_var(&mut self, o: O) -> &mut Self
    {
        self.result = Some(o);
        self
    }

    /// Supply a closure that the `RefMutExpectation` will use to create its
    /// return value.
    pub fn returning<F>(&mut self, f: F) -> &mut Self
        where F: FnMut(I) -> O + Send + 'static
    {
        mem::replace(&mut self.rfunc, Some(Box::new(f)));
        self
    }

    expectation_common!{common, RefMutExpectation}
}

impl<I, O> Default for RefMutExpectation<I, O> {
    fn default() -> Self {
        RefMutExpectation::new()
    }
}

impl<I, O> AnyExpectation for RefMutExpectation<I, O>
    where I: 'static, O: Send + 'static
{}

/// Non-generic keys to `GenericExpectation` internal storage
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct Key(any::TypeId);

impl Key {
    fn new<I: 'static, O: 'static>() -> Self {
        Key(any::TypeId::of::<(I, O)>())
    }
}

#[derive(Default)]
pub struct GenericExpectation {
    store: HashMap<Key, Box<dyn AnyExpectation>>
}

impl GenericExpectation {
    pub fn expect<'e, I, O>(&'e mut self) -> &'e mut Expectation<I, O>
        where I: 'static, O: 'static
    {
        let key = Key::new::<I, O>();
        let e = Box::new(Expectation::<I, O>::new());
        self.store.insert(key.clone(), e);
        self.store.get_mut(&key).unwrap()
            .downcast_mut()
            .unwrap()
    }

    // TODO: add a "called_nonstatic" method that can be used with types that
    // aren't 'static, and uses a different method to generate the key.
    pub fn call<I: 'static, O: 'static>(&self, args: I) -> O {
        let key = Key::new::<I, O>();
        let e: &Expectation<I, O> = self.store.get(&key)
            .expect("No matching expectation found")
            .downcast_ref()
            .unwrap();
        e.call(args)
    }
}

struct SeqHandle {
    inner: Arc<SeqInner>,
    seq: usize
}

impl SeqHandle {
    /// Tell the Sequence that this expectation has been fully satisfied
    fn satisfy(&self) {
        self.inner.satisfy(self.seq);
    }

    /// Verify that this handle was called in the correct order
    fn verify(&self) {
        self.inner.verify(self.seq);
    }
}

#[derive(Default)]
pub struct SeqInner {
    satisfaction_level: AtomicUsize,
}

impl SeqInner {
    /// Record the call identified by `seq` as fully satisfied.
    fn satisfy(&self, seq: usize) {
        let old_sl = self.satisfaction_level.fetch_add(1, Ordering::Relaxed);
        assert_eq!(old_sl, seq, "Method sequence violation.  Was an already-satisfied method called another time?");
    }

    /// Verify that the call identified by `seq` was called in the correct order
    fn verify(&self, seq: usize) {
        assert_eq!(seq, self.satisfaction_level.load(Ordering::Relaxed),
            "Method sequence violation")
    }
}

#[derive(Default)]
pub struct Sequence {
    inner: Arc<SeqInner>,
    next_seq: usize,
}

impl Sequence {
    pub fn new() -> Self {
        Self::default()
    }

    fn next(&mut self) -> SeqHandle {
        let handle = SeqHandle{inner: self.inner.clone(), seq: self.next_seq};
        self.next_seq += 1;
        handle
    }
}
<|endoftext|>


<commit_before>macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

fn main() {
    input! {
        n: usize,
    }
    println!("{}", n);
}
<commit_msg>update atcoder template<commit_after>#[allow(unused_macros)]
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };

    ($next:expr, mut $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, [ $t:tt ]) => {
        {
            let len = read_value!($next, usize);
            (0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
        }
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, bytes) => {
        read_value!($next, String).into_bytes()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

fn main() {
    input! {
        n: usize,
    }
    println!("{}", n);
}
<|endoftext|>


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

#[cfg(not(any(target_os = "linux", feature = "bcc-iosnoop")))]
mod stub {
    use crate::IOBytes;
    use crate::IOType;

    use std::cell::Cell;

    pub fn init() -> Result<(), String> {
        Err("No I/O tracing tool available".to_owned())
    }

    thread_local! {
        static IO_TYPE: Cell<IOType> = Cell::new(IOType::Other);
    }

    pub fn set_io_type(new_io_type: IOType) {
        IO_TYPE.with(|io_type| {
            io_type.set(new_io_type);
        });
    }

    pub fn get_io_type() -> IOType {
        IO_TYPE.with(|io_type| io_type.get())
    }

    pub fn fetch_io_bytes() -> [IOBytes; IOType::COUNT] {
        Default::default()
    }
}
#[cfg(not(any(target_os = "linux", feature = "bcc-iosnoop")))]
pub use stub::*;

#[cfg(all(target_os = "linux", feature = "bcc-iosnoop"))]
mod biosnoop;
#[cfg(all(target_os = "linux", feature = "bcc-iosnoop"))]
pub use biosnoop::*;

#[cfg(all(target_os = "linux", not(feature = "bcc-iosnoop")))]
mod proc;
#[cfg(all(target_os = "linux", not(feature = "bcc-iosnoop")))]
pub use proc::*;

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

    #[bench]
    fn bench_fetch_io_bytes(b: &mut test::Bencher) {
        let (tx, rx) = std::sync::mpsc::sync_channel(0);
        let _ths = (0..8)
            .map(|_| {
                let tx_clone = tx.clone();
                std::thread::Builder::new().spawn(move || {
                    set_io_type(IOType::ForegroundWrite);
                    tx_clone.send(()).unwrap();
                })
            })
            .collect::<Vec<_>>();
        b.iter(|| fetch_io_bytes());
        for _ in 0..8 {
            rx.recv().unwrap();
        }
    }

    #[bench]
    fn bench_set_io_type(b: &mut test::Bencher) {
        let (tx, rx) = std::sync::mpsc::sync_channel(0);
        let _ths = (0..8)
            .map(|_| {
                let tx_clone = tx.clone();
                std::thread::Builder::new().spawn(move || {
                    set_io_type(IOType::ForegroundWrite);
                    tx_clone.send(()).unwrap();
                })
            })
            .collect::<Vec<_>>();
        b.iter(|| match get_io_type() {
            IOType::ForegroundWrite => set_io_type(IOType::ForegroundRead),
            _ => set_io_type(IOType::ForegroundWrite),
        });
        for _ in 0..8 {
            rx.recv().unwrap();
        }
    }
}
<commit_msg>build: fix a Mac build issue (#12027)<commit_after>// Copyright 2022 TiKV Project Authors. Licensed under Apache-2.0.

#[cfg(not(any(target_os = "linux", feature = "bcc-iosnoop")))]
mod stub {
    use crate::IOBytes;
    use crate::IOType;

    use std::cell::Cell;
    use strum::EnumCount;

    pub fn init() -> Result<(), String> {
        Err("No I/O tracing tool available".to_owned())
    }

    thread_local! {
        static IO_TYPE: Cell<IOType> = Cell::new(IOType::Other);
    }

    pub fn set_io_type(new_io_type: IOType) {
        IO_TYPE.with(|io_type| {
            io_type.set(new_io_type);
        });
    }

    pub fn get_io_type() -> IOType {
        IO_TYPE.with(|io_type| io_type.get())
    }

    pub fn fetch_io_bytes() -> [IOBytes; IOType::COUNT] {
        Default::default()
    }
}
#[cfg(not(any(target_os = "linux", feature = "bcc-iosnoop")))]
pub use stub::*;

#[cfg(all(target_os = "linux", feature = "bcc-iosnoop"))]
mod biosnoop;
#[cfg(all(target_os = "linux", feature = "bcc-iosnoop"))]
pub use biosnoop::*;

#[cfg(all(target_os = "linux", not(feature = "bcc-iosnoop")))]
mod proc;
#[cfg(all(target_os = "linux", not(feature = "bcc-iosnoop")))]
pub use proc::*;

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

    #[bench]
    fn bench_fetch_io_bytes(b: &mut test::Bencher) {
        let (tx, rx) = std::sync::mpsc::sync_channel(0);
        let _ths = (0..8)
            .map(|_| {
                let tx_clone = tx.clone();
                std::thread::Builder::new().spawn(move || {
                    set_io_type(IOType::ForegroundWrite);
                    tx_clone.send(()).unwrap();
                })
            })
            .collect::<Vec<_>>();
        b.iter(|| fetch_io_bytes());
        for _ in 0..8 {
            rx.recv().unwrap();
        }
    }

    #[bench]
    fn bench_set_io_type(b: &mut test::Bencher) {
        let (tx, rx) = std::sync::mpsc::sync_channel(0);
        let _ths = (0..8)
            .map(|_| {
                let tx_clone = tx.clone();
                std::thread::Builder::new().spawn(move || {
                    set_io_type(IOType::ForegroundWrite);
                    tx_clone.send(()).unwrap();
                })
            })
            .collect::<Vec<_>>();
        b.iter(|| match get_io_type() {
            IOType::ForegroundWrite => set_io_type(IOType::ForegroundRead),
            _ => set_io_type(IOType::ForegroundWrite),
        });
        for _ in 0..8 {
            rx.recv().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use crate::{common::ui::{UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs},
            BLDR_URL_ENVVAR,
            ORIGIN_ENVVAR};
use habitat_common::cli_config::CliConfig;
use habitat_core::{package::target::PackageTarget,
                   AUTH_TOKEN_ENVVAR};
use same_file::is_same_file;
use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::{Path,
                 PathBuf}};

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";
pub const CERT_PATH_ENVVAR: &str = "CERT_PATH";
pub const SSL_CERT_FILE_ENVVAR: &str = "SSL_CERT_FILE";
pub const STUDIO_HOST_ARCH_ENVVAR: &str = "HAB_STUDIO_SECRET_HAB_STUDIO_HOST_ARCH";

const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

//  Set the environment variable for the host architecture to be used in
//  hab studio.  It must be set outside of studio and passed in through
//  the environment variable defined in STUDIO_HOST_ARCH_ENVVAR.
fn set_arch_env_var() {
    env::set_var(STUDIO_HOST_ARCH_ENVVAR,
                 format!("{}", PackageTarget::active_target()));
}

fn cache_ssl_cert_file(cert_file: &str, cert_cache_dir: &Path) -> Result<()> {
    let cert_path = Path::new(&cert_file);

    let cert_filename = match cert_path.file_name() {
        Some(cert_filename) => cert_filename,
        None => return Err(Error::CacheSslCertError(format!("{:?} is not a file", &cert_file))),
    };
    let cache_file = cert_cache_dir.join(&cert_filename);

    if cache_file.exists() && cert_path.exists() && is_same_file(&cache_file, &cert_path)? {
        return Err(Error::CacheSslCertError("Source and destination certificate are the same \
                                             file"
                                                  .to_string()));
    }

    debug!("Caching SSL_CERT_FILE {:?} => {:?}", cert_file, cache_file);
    stdfs::copy(cert_file, &cache_file)?;

    Ok(())
}

pub async fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = CliConfig::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR,
                            config.origin.map(|o| o.to_string()),
                            Sensitivity::PrintValue);

    set_arch_env_var();

    if config.ctl_secret.is_some() {
        ui.warn("Your Supervisor CtlGateway secret is not being copied to the Studio \
                 environment because the Studio's Supervisor is local. If you wish to contact a \
                 remote Supervisor from the Studio, please set the HAB_CTL_SECRET variable with \
                 your secret.")?;
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = &*fs::CACHE_KEY_PATH;
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    let ssl_path = match henv::var(CERT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_ssl_path(None::<&str>);
            debug!("Setting {}={}", CERT_PATH_ENVVAR, path.display());
            env::set_var(CERT_PATH_ENVVAR, &path);
            path
        }
    };
    if !ssl_path.is_dir() {
        debug!("Creating ssl_path at: {}", ssl_path.display());
        stdfs::create_dir_all(&ssl_path)?;
    }

    if let Ok(ssl_cert_file) = env::var(SSL_CERT_FILE_ENVVAR) {
        if let Err(err) = cache_ssl_cert_file(&ssl_cert_file, &ssl_path) {
            warn!("Unable to cache SSL_CERT_FILE: {}", err);
        }
    }

    inner::start(ui, args).await
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                VERSION};
    use habitat_core::{crypto::init,
                       env as henv,
                       fs::{am_i_root,
                            find_command},
                       os::process,
                       package::{PackageIdent,
                                 PackageInstall},
                       users};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";
    const STUDIO_CMD: &str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";

    pub async fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, args)?;
        if is_docker_studio(args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init()?;
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    let command = exec::command_from_min_pkg(ui, STUDIO_CMD, &ident).await?;
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    command
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> Result<bool> {
        let current_user = users::get_current_username()?.unwrap();
        let docker_members = users::get_members_by_groupname("docker")?;
        Ok(docker_members.map_or(false, |d| d.contains(&current_user)))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()?) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              str::FromStr};

    pub async fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(args) {
            start_windows_studio(_ui, args).await
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub async fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        init()?;
        let version: Vec<&str> = VERSION.split('/').collect();
        let ident =
            PackageIdent::from_str(&format!("{}/{}", super::STUDIO_PACKAGE_IDENT, version[0]))?;
        let pwsh_command = exec::command_from_min_pkg(ui, "pwsh.exe", &ident).await?;
        let studio_command = exec::command_from_min_pkg(ui, "hab-studio.ps1", &ident).await?;

        let mut cmd_args: Vec<OsString> = vec!["-NoProfile",
                                               "-ExecutionPolicy",
                                               "bypass",
                                               "-NoLogo",
                                               "-File"].into_iter()
                                                       .map(Into::into)
                                                       .collect();
        if let Some(cmd) = find_command(&studio_command) {
            cmd_args.push(cmd.into());
        } else {
            return Err(Error::ExecCommandNotFound(studio_command));
        }
        cmd_args.extend_from_slice(args);

        if let Some(cmd) = find_command(&pwsh_command) {
            // we need to disable the default ctrlc handler for this process (hab)
            // otherwise when a ctrlc is emitted in the studio, this process will
            // also respond to ctrlc which results in odd stdin/out behavior and
            // forces the user to close the console window entirely
            ctrlc::set_handler(move || {})?;
            process::become_command(cmd, &cmd_args)?;
        } else {
            return Err(Error::ExecCommandNotFound(pwsh_command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use super::cache_ssl_cert_file;
    use std::fs::File;
    use tempfile::TempDir;

    #[test]
    fn cache_ssl_cert_file_caches_file() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(cert_name);
        File::create(&ssl_cert_filepath)?;

        cache_ssl_cert_file(ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();
        assert!(cert_cache_dir.join(cert_name).exists());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_replaces_already_cached() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";

        let cert_cache_dir = TempDir::new()?.into_path();
        let cached_cert = cert_cache_dir.join(&cert_name);
        File::create(&cached_cert)?;

        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(&cert_name);
        std::fs::write(&ssl_cert_filepath, "new cert from environment")?;

        cache_ssl_cert_file(ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();

        let contents = std::fs::read_to_string(&cached_cert)?;

        assert_eq!(contents, "new cert from environment");

        Ok(())
    }
    #[test]
    fn cache_ssl_cert_file_invalid_file() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();

        let non_existant_file_name = "i_shouldnt_exist";
        let non_existant_file = TempDir::new()?.path().join(non_existant_file_name);

        assert!(cache_ssl_cert_file(non_existant_file.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_dir() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file(ssl_cert_dir.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_cached_file() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();
        let cached_cert = cached_cert_dir.join("ssl-cert-file.pem");
        File::create(&cached_cert)?;

        assert!(cache_ssl_cert_file(cached_cert.to_str().unwrap(), &cached_cert_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_is_empty_string() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file("", &cached_cert_dir).is_err());

        Ok(())
    }
}
<commit_msg>rustfmt<commit_after>use crate::{common::ui::{UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs},
            BLDR_URL_ENVVAR,
            ORIGIN_ENVVAR};
use habitat_common::cli_config::CliConfig;
use habitat_core::{package::target::PackageTarget,
                   AUTH_TOKEN_ENVVAR};
use same_file::is_same_file;
use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::{Path,
                 PathBuf}};

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";
pub const CERT_PATH_ENVVAR: &str = "CERT_PATH";
pub const SSL_CERT_FILE_ENVVAR: &str = "SSL_CERT_FILE";
pub const STUDIO_HOST_ARCH_ENVVAR: &str = "HAB_STUDIO_SECRET_HAB_STUDIO_HOST_ARCH";

const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

//  Set the environment variable for the host architecture to be used in
//  hab studio.  It must be set outside of studio and passed in through
//  the environment variable defined in STUDIO_HOST_ARCH_ENVVAR.
fn set_arch_env_var() {
    env::set_var(STUDIO_HOST_ARCH_ENVVAR,
                 format!("{}", PackageTarget::active_target()));
}

fn cache_ssl_cert_file(cert_file: &str, cert_cache_dir: &Path) -> Result<()> {
    let cert_path = Path::new(&cert_file);

    let cert_filename = match cert_path.file_name() {
        Some(cert_filename) => cert_filename,
        None => return Err(Error::CacheSslCertError(format!("{:?} is not a file", &cert_file))),
    };
    let cache_file = cert_cache_dir.join(&cert_filename);

    if cache_file.exists() && cert_path.exists() && is_same_file(&cache_file, &cert_path)? {
        return Err(Error::CacheSslCertError("Source and destination certificate are the same \
                                             file"
                                                  .to_string()));
    }

    debug!("Caching SSL_CERT_FILE {:?} => {:?}", cert_file, cache_file);
    stdfs::copy(cert_file, &cache_file)?;

    Ok(())
}

pub async fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = CliConfig::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR,
                            config.origin.map(|o| o.to_string()),
                            Sensitivity::PrintValue);

    set_arch_env_var();

    if config.ctl_secret.is_some() {
        ui.warn("Your Supervisor CtlGateway secret is not being copied to the Studio \
                 environment because the Studio's Supervisor is local. If you wish to contact a \
                 remote Supervisor from the Studio, please set the HAB_CTL_SECRET variable with \
                 your secret.")?;
    }

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = &*fs::CACHE_KEY_PATH;
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    let ssl_path = match henv::var(CERT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_ssl_path(None::<&str>);
            debug!("Setting {}={}", CERT_PATH_ENVVAR, path.display());
            env::set_var(CERT_PATH_ENVVAR, &path);
            path
        }
    };
    if !ssl_path.is_dir() {
        debug!("Creating ssl_path at: {}", ssl_path.display());
        stdfs::create_dir_all(&ssl_path)?;
    }

    if let Ok(ssl_cert_file) = env::var(SSL_CERT_FILE_ENVVAR) {
        if let Err(err) = cache_ssl_cert_file(&ssl_cert_file, &ssl_path) {
            warn!("Unable to cache SSL_CERT_FILE: {}", err);
        }
    }

    inner::start(ui, args).await
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                VERSION};
    use habitat_core::{crypto::init,
                       env as henv,
                       fs::{am_i_root,
                            find_command},
                       os::process,
                       package::{PackageIdent,
                                 PackageInstall},
                       users};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";
    const STUDIO_CMD: &str = "hab-studio";
    const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";

    pub async fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, args)?;
        if is_docker_studio(args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init()?;
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    let command = exec::command_from_min_pkg(ui, STUDIO_CMD, &ident).await?;
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    command
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> Result<bool> {
        let current_user = users::get_current_username()?.unwrap();
        let docker_members = users::get_members_by_groupname("docker")?;
        Ok(docker_members.map_or(false, |d| d.contains(&current_user)))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()?) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              str::FromStr};

    pub async fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(args) {
            start_windows_studio(_ui, args).await
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub async fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        init()?;
        let version: Vec<&str> = VERSION.split('/').collect();
        let ident =
            PackageIdent::from_str(&format!("{}/{}", super::STUDIO_PACKAGE_IDENT, version[0]))?;
        let pwsh_command = exec::command_from_min_pkg(ui, "pwsh.exe", &ident).await?;
        let studio_command = exec::command_from_min_pkg(ui, "hab-studio.ps1", &ident).await?;

        let mut cmd_args: Vec<OsString> = vec!["-NoProfile",
                                               "-ExecutionPolicy",
                                               "bypass",
                                               "-NoLogo",
                                               "-File"].into_iter()
                                                       .map(Into::into)
                                                       .collect();
        if let Some(cmd) = find_command(&studio_command) {
            cmd_args.push(cmd.into());
        } else {
            return Err(Error::ExecCommandNotFound(studio_command));
        }
        cmd_args.extend_from_slice(args);

        if let Some(cmd) = find_command(&pwsh_command) {
            // we need to disable the default ctrlc handler for this process (hab)
            // otherwise when a ctrlc is emitted in the studio, this process will
            // also respond to ctrlc which results in odd stdin/out behavior and
            // forces the user to close the console window entirely
            ctrlc::set_handler(move || {})?;
            process::become_command(cmd, &cmd_args)?;
        } else {
            return Err(Error::ExecCommandNotFound(pwsh_command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use super::cache_ssl_cert_file;
    use std::fs::File;
    use tempfile::TempDir;

    #[test]
    fn cache_ssl_cert_file_caches_file() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(cert_name);
        File::create(&ssl_cert_filepath)?;

        cache_ssl_cert_file(ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();
        assert!(cert_cache_dir.join(cert_name).exists());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_replaces_already_cached() -> std::io::Result<()> {
        let cert_name = "ssl-test-cert.pem";

        let cert_cache_dir = TempDir::new()?.into_path();
        let cached_cert = cert_cache_dir.join(&cert_name);
        File::create(&cached_cert)?;

        let ssl_cert_dir = TempDir::new()?;
        let ssl_cert_filepath = ssl_cert_dir.path().join(&cert_name);
        std::fs::write(&ssl_cert_filepath, "new cert from environment")?;

        cache_ssl_cert_file(ssl_cert_filepath.to_str().unwrap(), &cert_cache_dir).unwrap();

        let contents = std::fs::read_to_string(&cached_cert)?;

        assert_eq!(contents, "new cert from environment");

        Ok(())
    }
    #[test]
    fn cache_ssl_cert_file_invalid_file() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();

        let non_existant_file_name = "i_shouldnt_exist";
        let non_existant_file = TempDir::new()?.path().join(non_existant_file_name);

        assert!(cache_ssl_cert_file(non_existant_file.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_dir() -> std::io::Result<()> {
        let cert_cache_dir = TempDir::new()?.into_path();
        let ssl_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file(ssl_cert_dir.to_str().unwrap(), &cert_cache_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_cert_file_is_cached_file() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();
        let cached_cert = cached_cert_dir.join("ssl-cert-file.pem");
        File::create(&cached_cert)?;

        assert!(cache_ssl_cert_file(cached_cert.to_str().unwrap(), &cached_cert_dir).is_err());

        Ok(())
    }

    #[test]
    fn cache_ssl_cert_file_is_empty_string() -> std::io::Result<()> {
        let cached_cert_dir = TempDir::new()?.into_path();

        assert!(cache_ssl_cert_file("", &cached_cert_dir).is_err());

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! VN text corrector

extern crate clipboard_win;
use clipboard_win::{set_clipboard, ClipboardManager};
pub mod utils;

fn handler_clip_text(text: &String) {
    if !utils::is_jp(text) { return; }

    const BEGIN: &'static[char] = &['「', '（'];
    const END: &'static[char] = &['」', '）'];
    if let (Some(begin_pos), Some(end_pos)) = (text.find(BEGIN), text.find(END)) {
        let end_pos = end_pos + 3; //+3 to go at the symbol of dialogue end
        if end_pos == text.len() { return; }

        println!(">>>Action:");
        if set_clipboard(&text[begin_pos..end_pos]).is_err() {
            println!("Hmph... failed to update clipboard");
        }
        else {
            println!("Dialogue is extracted");
        }
    }
}

fn main() {
    println!("####################################");
    println!("#        VN text corrector         #");
    println!("####################################");
    ClipboardManager::new().delay(10).ok_callback(handler_clip_text).run();
}
<commit_msg>VN script: trim of newlines<commit_after>//! VN text corrector

extern crate clipboard_win;
use clipboard_win::{set_clipboard, ClipboardManager};
pub mod utils;

fn handler_clip_text(text: &String) {
    if !utils::is_jp(text) { return; }

    const BEGIN: &'static[char] = &['「', '（'];
    const END: &'static[char] = &['」', '）'];
    if let (Some(begin_pos), Some(end_pos)) = (text.find(BEGIN), text.find(END)) {
        let end_pos = end_pos + 3; //+3 to go at the symbol of dialogue end
        if end_pos == text.len() { return; }

        println!(">>>Action:");
        if set_clipboard(&text[begin_pos..end_pos].replace("\n", "")).is_err() {
            println!("Hmph... failed to update clipboard");
        }
        else {
            println!("Dialogue is extracted");
        }
    }
}

fn main() {
    println!("####################################");
    println!("#        VN text corrector         #");
    println!("####################################");
    ClipboardManager::new().delay(10).ok_callback(handler_clip_text).run();
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use metrics::Metric;
use reporter::Reporter;
use std::time::Duration;
use std::thread;

pub struct ConsoleReporter {
    metrics: Vec<Metric>,
    reporter_name: &'static str,
}

impl Reporter for ConsoleReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

impl ConsoleReporter {
    pub fn new(reporter_name: &'static str) -> Self {
        ConsoleReporter {
            metrics: vec![],
            reporter_name: reporter_name,
        }
    }

    pub fn add(&mut self, metric: Metric) {
        self.metrics.push(metric);
    }

    pub fn start(self, delay_ms: u64) {
        thread::spawn(move || {
            loop {
                for metric in &self.metrics {
                    match *metric {
                        Metric::Meter(ref x) => {
                            println!("{:?}", x.snapshot());
                        }
                        Metric::Gauge(ref x) => {
                            println!("{:?}", x.snapshot());
                        }
                        Metric::Counter(ref x) => {
                            println!("{:?}", x.snapshot());
                        }
                        Metric::Histogram(ref x) => {
                            println!("histogram{:?}", x);
                        }
                    }
                }
                thread::sleep(Duration::from_millis(delay_ms));
            }
        });
    }
}

#[cfg(test)]
mod test {

    use histogram::Histogram;
    use metrics::{Counter, Gauge, Meter, Metric, StdCounter, StdGauge, StdMeter};
    use std::thread;
    use std::time::Duration;
    use super::ConsoleReporter;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let c = StdCounter::new();
        c.inc();

        let g = StdGauge::new();
        g.set(2);

        let mut h = Histogram::configure()
            .max_value(100)
            .precision(1)
            .build()
            .unwrap();

        h.increment_by(1, 1).unwrap();

        let mut reporter = ConsoleReporter::new("test");
        reporter.add(Metric::Meter(m.clone()));
        reporter.add(Metric::Counter(c.clone()));
        reporter.add(Metric::Gauge(g.clone()));
        reporter.add(Metric::Histogram(h));
        reporter.start(1);
        g.set(4);
        thread::sleep(Duration::from_millis(200));
        println!("poplopit");
    }
}
<commit_msg>add a stop<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use metrics::Metric;
use reporter::Reporter;
use std::sync::Arc;
use std::time::Duration;
use std::thread;
use std::sync::mpsc;

pub struct ConsoleReporter {
    metrics: mpsc::Sender<Option<Metric>>,
    reporter_name: &'static str,
}

impl Reporter for ConsoleReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

impl ConsoleReporter {
    pub fn new(reporter_name: &'static str, delay_ms: u64) -> Self {
        let (tx, rx) = mpsc::channel();
        let reporter = ConsoleReporter {
            metrics: tx,
            reporter_name: reporter_name
        };

        thread::spawn(move || {
            let mut stop = false;
            while !stop {
                for metric in &rx {
                    match metric {
                        Some(metric) => {
                            match metric {
                                Metric::Meter(ref x) => {
                                    println!("{:?}", x.snapshot());
                                }
                                Metric::Gauge(ref x) => {
                                    println!("{:?}", x.snapshot());
                                }
                                Metric::Counter(ref x) => {
                                    println!("{:?}", x.snapshot());
                                }
                                Metric::Histogram(ref x) => {
                                    println!("histogram{:?}", x);
                                }
                            }
                        }
                        None => stop = true,
                    }

                    thread::sleep(Duration::from_millis(delay_ms));
                }
            }
        });
        reporter
    }

    pub fn add(&mut self, metric: Metric) {
        self.metrics.send(Some(metric));
    }
    pub fn stop(&mut self) {
        self.metrics.send(None);
    }
}

#[cfg(test)]
mod test {

    use histogram::Histogram;
    use metrics::{Counter, Gauge, Meter, Metric, StdCounter, StdGauge, StdMeter};
    use std::thread;
    use std::time::Duration;
    use super::ConsoleReporter;

    #[test]
    fn meter() {
        let m = StdMeter::new();
        m.mark(100);

        let c = StdCounter::new();
        c.inc();

        let g = StdGauge::new();
        g.set(2);

        let mut h = Histogram::configure()
            .max_value(100)
            .precision(1)
            .build()
            .unwrap();

        h.increment_by(1, 1).unwrap();

        let mut reporter = ConsoleReporter::new("test", 1);
        reporter.add(Metric::Meter(m.clone()));
        reporter.add(Metric::Counter(c.clone()));
        reporter.add(Metric::Gauge(g.clone()));
        reporter.add(Metric::Histogram(h));
        g.set(4);
        thread::sleep(Duration::from_millis(200));
        reporter.stop();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use libra_crypto_derive::{CryptoHasher, LCSCryptoHash};
use libra_types::block_info::BlockInfo;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};

/// VoteData keeps the information about the block, and its parent.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, CryptoHasher, LCSCryptoHash)]
pub struct VoteData {
    /// Contains all the block information needed for voting for the proposed round.
    proposed: BlockInfo,
    /// Contains all the block information for the parent for the proposed round.
    parent: BlockInfo,
}

impl Display for VoteData {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "VoteData: [block id: {}, epoch: {}, round: {:02}, parent_block_id: {}, parent_block_round: {:02}]",
            self.proposed().id(), self.proposed().epoch(), self.proposed().round(), self.parent().id(), self.parent().round(),
        )
    }
}

impl VoteData {
    pub fn new(proposed: BlockInfo, parent: BlockInfo) -> Self {
        Self { proposed, parent }
    }

    /// Contains all the block information needed for voting for the proposed round.
    pub fn parent(&self) -> &BlockInfo {
        &self.parent
    }

    /// Contains all the block information for the parent for the proposed round.
    pub fn proposed(&self) -> &BlockInfo {
        &self.proposed
    }

    pub fn verify(&self) -> anyhow::Result<()> {
        anyhow::ensure!(
            self.parent.epoch() == self.proposed.epoch(),
            "Parent and proposed epochs do not match",
        );
        anyhow::ensure!(
            self.parent.round() < self.proposed.round(),
            "Proposed round is less than parent round",
        );
        anyhow::ensure!(
            self.parent.timestamp_usecs() <= self.proposed.timestamp_usecs(),
            "Proposed happened before parent",
        );
        anyhow::ensure!(
            self.parent.version() <= self.proposed.version(),
            "Proposed version is less than parent version",
        );
        Ok(())
    }
}
<commit_msg>[consensus][easy] fixes swapped comments + add doc<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use libra_crypto_derive::{CryptoHasher, LCSCryptoHash};
use libra_types::block_info::BlockInfo;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};

/// VoteData keeps the information about the block, and its parent.
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, CryptoHasher, LCSCryptoHash)]
pub struct VoteData {
    /// Contains all the block information needed for voting for the proposed round.
    proposed: BlockInfo,
    /// Contains all the block information for the block the proposal is extending.
    parent: BlockInfo,
}

impl Display for VoteData {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "VoteData: [block id: {}, epoch: {}, round: {:02}, parent_block_id: {}, parent_block_round: {:02}]",
            self.proposed().id(), self.proposed().epoch(), self.proposed().round(), self.parent().id(), self.parent().round(),
        )
    }
}

impl VoteData {
    /// Constructs a new VoteData from the block information of a proposed block and the block it extends.
    pub fn new(proposed: BlockInfo, parent: BlockInfo) -> Self {
        Self { proposed, parent }
    }

    /// Returns block information associated to the block being extended by the proposal.
    pub fn parent(&self) -> &BlockInfo {
        &self.parent
    }

    /// Returns block information associated to the block being voted on.
    pub fn proposed(&self) -> &BlockInfo {
        &self.proposed
    }

    /// Well-formedness checks that are independent of the current state.
    pub fn verify(&self) -> anyhow::Result<()> {
        anyhow::ensure!(
            self.parent.epoch() == self.proposed.epoch(),
            "Parent and proposed epochs do not match",
        );
        anyhow::ensure!(
            self.parent.round() < self.proposed.round(),
            "Proposed round is less than parent round",
        );
        anyhow::ensure!(
            self.parent.timestamp_usecs() <= self.proposed.timestamp_usecs(),
            "Proposed happened before parent",
        );
        anyhow::ensure!(
            self.parent.version() <= self.proposed.version(),
            "Proposed version is less than parent version",
        );
        Ok(())
    }
}
<|endoftext|>