<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/. */

//! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports)

use cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token};
use cssparser::{ParseError as CssParseError, ParserInput};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{ToCss, ParseError};
use stylesheets::{CssRuleType, CssRules};

/// An [`@supports`][supports] rule.
///
/// [supports]: https://drafts.csswg.org/css-conditional-3/#at-supports
#[derive(Debug)]
pub struct SupportsRule {
    /// The parsed condition
    pub condition: SupportsCondition,
    /// Child rules
    pub rules: Arc<Locked<CssRules>>,
    /// The result of evaluating the condition
    pub enabled: bool,
    /// The line and column of the rule's source code.
    pub source_location: SourceLocation,
}

impl SupportsRule {
    /// Measure heap usage.
    #[cfg(feature = "gecko")]
    pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
        // Measurement of other fields may be added later.
        self.rules.unconditional_shallow_size_of(ops) +
            self.rules.read_with(guard).size_of(guard, ops)
    }
}

impl ToCssWithGuard for SupportsRule {
    fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        dest.write_str("@supports ")?;
        self.condition.to_css(dest)?;
        self.rules.read_with(guard).to_css_block(guard, dest)
    }
}

impl DeepCloneWithLock for SupportsRule {
    fn deep_clone_with_lock(
        &self,
        lock: &SharedRwLock,
        guard: &SharedRwLockReadGuard,
        params: &DeepCloneParams,
    ) -> Self {
        let rules = self.rules.read_with(guard);
        SupportsRule {
            condition: self.condition.clone(),
            rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
            enabled: self.enabled,
            source_location: self.source_location.clone(),
        }
    }
}

/// An @supports condition
///
/// <https://drafts.csswg.org/css-conditional-3/#at-supports>
#[derive(Clone, Debug)]
pub enum SupportsCondition {
    /// `not (condition)`
    Not(Box<SupportsCondition>),
    /// `(condition)`
    Parenthesized(Box<SupportsCondition>),
    /// `(condition) and (condition) and (condition) ..`
    And(Vec<SupportsCondition>),
    /// `(condition) or (condition) or (condition) ..`
    Or(Vec<SupportsCondition>),
    /// `property-ident: value` (value can be any tokens)
    Declaration(Declaration),
    /// `(any tokens)` or `func(any tokens)`
    FutureSyntax(String),
}

impl SupportsCondition {
    /// Parse a condition
    ///
    /// <https://drafts.csswg.org/css-conditional/#supports_condition>
    pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
        if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) {
            let inner = SupportsCondition::parse_in_parens(input)?;
            return Ok(SupportsCondition::Not(Box::new(inner)));
        }

        let in_parens = SupportsCondition::parse_in_parens(input)?;

        let location = input.current_source_location();
        let (keyword, wrapper) = match input.next() {
            Err(_) => {
                // End of input
                return Ok(in_parens)
            }
            Ok(&Token::Ident(ref ident)) => {
                match_ignore_ascii_case! { &ident,
                    "and" => ("and", SupportsCondition::And as fn(_) -> _),
                    "or" => ("or", SupportsCondition::Or as fn(_) -> _),
                    _ => return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
                }
            }
            Ok(t) => return Err(location.new_unexpected_token_error(t.clone()))
        };

        let mut conditions = Vec::with_capacity(2);
        conditions.push(in_parens);
        loop {
            conditions.push(SupportsCondition::parse_in_parens(input)?);
            if input.try(|input| input.expect_ident_matching(keyword)).is_err() {
                // Did not find the expected keyword.
                // If we found some other token,
                // it will be rejected by `Parser::parse_entirely` somewhere up the stack.
                return Ok(wrapper(conditions))
            }
        }
    }

    /// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens>
    fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
        // Whitespace is normally taken care of in `Parser::next`,
        // but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
        while input.try(Parser::expect_whitespace).is_ok() {}
        let pos = input.position();
        let location = input.current_source_location();
        // FIXME: remove clone() when lifetimes are non-lexical
        match input.next()?.clone() {
            Token::ParenthesisBlock => {
                let nested = input.try(|input| {
                    input.parse_nested_block(|i| parse_condition_or_declaration(i))
                });
                if nested.is_ok() {
                    return nested;
                }
            }
            Token::Function(_) => {}
            t => return Err(location.new_unexpected_token_error(t)),
        }
        input.parse_nested_block(|i| consume_any_value(i))?;
        Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned()))
    }

    /// Evaluate a supports condition
    pub fn eval(&self, cx: &ParserContext) -> bool {
        match *self {
            SupportsCondition::Not(ref cond) => !cond.eval(cx),
            SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
            SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
            SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
            SupportsCondition::Declaration(ref decl) => decl.eval(cx),
            SupportsCondition::FutureSyntax(_) => false
        }
    }
}

/// supports_condition | declaration
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext>
pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>)
                                              -> Result<SupportsCondition, ParseError<'i>> {
    if let Ok(condition) = input.try(SupportsCondition::parse) {
        Ok(SupportsCondition::Parenthesized(Box::new(condition)))
    } else {
        Declaration::parse(input).map(SupportsCondition::Declaration)
    }
}

impl ToCss for SupportsCondition {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            SupportsCondition::Not(ref cond) => {
                dest.write_str("not ")?;
                cond.to_css(dest)
            }
            SupportsCondition::Parenthesized(ref cond) => {
                dest.write_str("(")?;
                cond.to_css(dest)?;
                dest.write_str(")")
            }
            SupportsCondition::And(ref vec) => {
                let mut first = true;
                for cond in vec {
                    if !first {
                        dest.write_str(" and ")?;
                    }
                    first = false;
                    cond.to_css(dest)?;
                }
                Ok(())
            }
            SupportsCondition::Or(ref vec) => {
                let mut first = true;
                for cond in vec {
                    if !first {
                        dest.write_str(" or ")?;
                    }
                    first = false;
                    cond.to_css(dest)?;
                }
                Ok(())
            }
            SupportsCondition::Declaration(ref decl) => {
                dest.write_str("(")?;
                decl.to_css(dest)?;
                dest.write_str(")")
            }
            SupportsCondition::FutureSyntax(ref s) => dest.write_str(&s),
        }
    }
}

#[derive(Clone, Debug)]
/// A possibly-invalid property declaration
pub struct Declaration(pub String);

impl ToCss for Declaration {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str(&self.0)
    }
}

/// <https://drafts.csswg.org/css-syntax-3/#typedef-any-value>
fn consume_any_value<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> {
    input.expect_no_error_token().map_err(|err| err.into())
}

impl Declaration {
    /// Parse a declaration
    pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Declaration, ParseError<'i>> {
        let pos = input.position();
        input.expect_ident()?;
        input.expect_colon()?;
        consume_any_value(input)?;
        Ok(Declaration(input.slice_from(pos).to_owned()))
    }

    /// Determine if a declaration parses
    ///
    /// <https://drafts.csswg.org/css-conditional-3/#support-definition>
    pub fn eval(&self, context: &ParserContext) -> bool {
        debug_assert_eq!(context.rule_type(), CssRuleType::Style);

        let mut input = ParserInput::new(&self.0);
        let mut input = Parser::new(&mut input);
        input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
            let prop = input.expect_ident().unwrap().as_ref().to_owned();
            input.expect_colon().unwrap();

            let id = PropertyId::parse(&prop)
                .map_err(|_| input.new_custom_error(()))?;

            let mut declarations = SourcePropertyDeclaration::new();
            input.parse_until_before(Delimiter::Bang, |input| {
                PropertyDeclaration::parse_into(&mut declarations, id, prop.into(), &context, input)
                    .map_err(|_| input.new_custom_error(()))
            })?;
            let _ = input.try(parse_important);
            Ok(())
        }).is_ok()
    }
}
<commit_msg>style: Avoid unneessary malloc churn when evaluating @supports rules.<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/. */

//! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports)

use cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token};
use cssparser::{ParseError as CssParseError, ParserInput};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{ToCss, ParseError};
use stylesheets::{CssRuleType, CssRules};

/// An [`@supports`][supports] rule.
///
/// [supports]: https://drafts.csswg.org/css-conditional-3/#at-supports
#[derive(Debug)]
pub struct SupportsRule {
    /// The parsed condition
    pub condition: SupportsCondition,
    /// Child rules
    pub rules: Arc<Locked<CssRules>>,
    /// The result of evaluating the condition
    pub enabled: bool,
    /// The line and column of the rule's source code.
    pub source_location: SourceLocation,
}

impl SupportsRule {
    /// Measure heap usage.
    #[cfg(feature = "gecko")]
    pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
        // Measurement of other fields may be added later.
        self.rules.unconditional_shallow_size_of(ops) +
            self.rules.read_with(guard).size_of(guard, ops)
    }
}

impl ToCssWithGuard for SupportsRule {
    fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        dest.write_str("@supports ")?;
        self.condition.to_css(dest)?;
        self.rules.read_with(guard).to_css_block(guard, dest)
    }
}

impl DeepCloneWithLock for SupportsRule {
    fn deep_clone_with_lock(
        &self,
        lock: &SharedRwLock,
        guard: &SharedRwLockReadGuard,
        params: &DeepCloneParams,
    ) -> Self {
        let rules = self.rules.read_with(guard);
        SupportsRule {
            condition: self.condition.clone(),
            rules: Arc::new(lock.wrap(rules.deep_clone_with_lock(lock, guard, params))),
            enabled: self.enabled,
            source_location: self.source_location.clone(),
        }
    }
}

/// An @supports condition
///
/// <https://drafts.csswg.org/css-conditional-3/#at-supports>
#[derive(Clone, Debug)]
pub enum SupportsCondition {
    /// `not (condition)`
    Not(Box<SupportsCondition>),
    /// `(condition)`
    Parenthesized(Box<SupportsCondition>),
    /// `(condition) and (condition) and (condition) ..`
    And(Vec<SupportsCondition>),
    /// `(condition) or (condition) or (condition) ..`
    Or(Vec<SupportsCondition>),
    /// `property-ident: value` (value can be any tokens)
    Declaration(Declaration),
    /// `(any tokens)` or `func(any tokens)`
    FutureSyntax(String),
}

impl SupportsCondition {
    /// Parse a condition
    ///
    /// <https://drafts.csswg.org/css-conditional/#supports_condition>
    pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
        if let Ok(_) = input.try(|i| i.expect_ident_matching("not")) {
            let inner = SupportsCondition::parse_in_parens(input)?;
            return Ok(SupportsCondition::Not(Box::new(inner)));
        }

        let in_parens = SupportsCondition::parse_in_parens(input)?;

        let location = input.current_source_location();
        let (keyword, wrapper) = match input.next() {
            Err(_) => {
                // End of input
                return Ok(in_parens)
            }
            Ok(&Token::Ident(ref ident)) => {
                match_ignore_ascii_case! { &ident,
                    "and" => ("and", SupportsCondition::And as fn(_) -> _),
                    "or" => ("or", SupportsCondition::Or as fn(_) -> _),
                    _ => return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
                }
            }
            Ok(t) => return Err(location.new_unexpected_token_error(t.clone()))
        };

        let mut conditions = Vec::with_capacity(2);
        conditions.push(in_parens);
        loop {
            conditions.push(SupportsCondition::parse_in_parens(input)?);
            if input.try(|input| input.expect_ident_matching(keyword)).is_err() {
                // Did not find the expected keyword.
                // If we found some other token,
                // it will be rejected by `Parser::parse_entirely` somewhere up the stack.
                return Ok(wrapper(conditions))
            }
        }
    }

    /// <https://drafts.csswg.org/css-conditional-3/#supports_condition_in_parens>
    fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<SupportsCondition, ParseError<'i>> {
        // Whitespace is normally taken care of in `Parser::next`,
        // but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
        while input.try(Parser::expect_whitespace).is_ok() {}
        let pos = input.position();
        let location = input.current_source_location();
        // FIXME: remove clone() when lifetimes are non-lexical
        match input.next()?.clone() {
            Token::ParenthesisBlock => {
                let nested = input.try(|input| {
                    input.parse_nested_block(|i| parse_condition_or_declaration(i))
                });
                if nested.is_ok() {
                    return nested;
                }
            }
            Token::Function(_) => {}
            t => return Err(location.new_unexpected_token_error(t)),
        }
        input.parse_nested_block(|i| consume_any_value(i))?;
        Ok(SupportsCondition::FutureSyntax(input.slice_from(pos).to_owned()))
    }

    /// Evaluate a supports condition
    pub fn eval(&self, cx: &ParserContext) -> bool {
        match *self {
            SupportsCondition::Not(ref cond) => !cond.eval(cx),
            SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
            SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
            SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
            SupportsCondition::Declaration(ref decl) => decl.eval(cx),
            SupportsCondition::FutureSyntax(_) => false
        }
    }
}

/// supports_condition | declaration
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports-conditiontext-conditiontext>
pub fn parse_condition_or_declaration<'i, 't>(input: &mut Parser<'i, 't>)
                                              -> Result<SupportsCondition, ParseError<'i>> {
    if let Ok(condition) = input.try(SupportsCondition::parse) {
        Ok(SupportsCondition::Parenthesized(Box::new(condition)))
    } else {
        Declaration::parse(input).map(SupportsCondition::Declaration)
    }
}

impl ToCss for SupportsCondition {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match *self {
            SupportsCondition::Not(ref cond) => {
                dest.write_str("not ")?;
                cond.to_css(dest)
            }
            SupportsCondition::Parenthesized(ref cond) => {
                dest.write_str("(")?;
                cond.to_css(dest)?;
                dest.write_str(")")
            }
            SupportsCondition::And(ref vec) => {
                let mut first = true;
                for cond in vec {
                    if !first {
                        dest.write_str(" and ")?;
                    }
                    first = false;
                    cond.to_css(dest)?;
                }
                Ok(())
            }
            SupportsCondition::Or(ref vec) => {
                let mut first = true;
                for cond in vec {
                    if !first {
                        dest.write_str(" or ")?;
                    }
                    first = false;
                    cond.to_css(dest)?;
                }
                Ok(())
            }
            SupportsCondition::Declaration(ref decl) => {
                dest.write_str("(")?;
                decl.to_css(dest)?;
                dest.write_str(")")
            }
            SupportsCondition::FutureSyntax(ref s) => dest.write_str(&s),
        }
    }
}

#[derive(Clone, Debug)]
/// A possibly-invalid property declaration
pub struct Declaration(pub String);

impl ToCss for Declaration {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str(&self.0)
    }
}

/// <https://drafts.csswg.org/css-syntax-3/#typedef-any-value>
fn consume_any_value<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> {
    input.expect_no_error_token().map_err(|err| err.into())
}

impl Declaration {
    /// Parse a declaration
    pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Declaration, ParseError<'i>> {
        let pos = input.position();
        input.expect_ident()?;
        input.expect_colon()?;
        consume_any_value(input)?;
        Ok(Declaration(input.slice_from(pos).to_owned()))
    }

    /// Determine if a declaration parses
    ///
    /// <https://drafts.csswg.org/css-conditional-3/#support-definition>
    pub fn eval(&self, context: &ParserContext) -> bool {
        debug_assert_eq!(context.rule_type(), CssRuleType::Style);

        let mut input = ParserInput::new(&self.0);
        let mut input = Parser::new(&mut input);
        input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
            let prop = input.expect_ident_cloned().unwrap();
            input.expect_colon().unwrap();

            let id = PropertyId::parse(&prop)
                .map_err(|_| input.new_custom_error(()))?;

            let mut declarations = SourcePropertyDeclaration::new();
            input.parse_until_before(Delimiter::Bang, |input| {
                PropertyDeclaration::parse_into(&mut declarations, id, prop, &context, input)
                    .map_err(|_| input.new_custom_error(()))
            })?;
            let _ = input.try(parse_important);
            Ok(())
        }).is_ok()
    }
}
<|endoftext|>


<commit_before>/// Enum mapping type
///
/// This trait is internally used by `#[derive(Enum)]`. `Enum<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    /// Number of possible values the type can have.
    const POSSIBLE_VALUES: usize;
    /// Gets a slice from an array type.
    fn slice(array: &Self::Array) -> &[V];
    /// Gets a mutable slice from an array type.
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    /// Takes an usize, and returns an element matching `to_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..POSSIBLE_VALUES`.
    fn to_usize(self) -> usize;
    /// Creates an array using a function called for each argument.
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Enum<T> for bool {
    type Array = [T; 2];
    const POSSIBLE_VALUES: usize = 2;
    #[inline]
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    #[inline]
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn to_usize(self) -> usize {
        self as usize
    }
    #[inline]
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Enum<T> for u8 {
    type Array = [T; 256];
    const POSSIBLE_VALUES: usize = 256;
    #[inline]
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    #[inline]
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    #[inline]
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    #[inline]
    fn to_usize(self) -> usize {
        self as usize
    }
    #[inline]
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}
<commit_msg>Use word states for POSSIBLE_VALUES comment<commit_after>/// Enum mapping type
///
/// This trait is internally used by `#[derive(Enum)]`. `Enum<T>` is
/// implemented by any enum type where V is a generic type representing a
/// value. The purpose of this generic type is to allow providing a value
/// type for arrays, as Rust currently does not support higher kinded types.
///
/// This trait is also implemented by `bool` and `u8`. While `u8` is
/// strictly speaking not an actual enum, there are good reasons to consider
/// it like one, as array of `u8` keys is a relatively common pattern.
pub trait Enum<V>: Sized {
    /// Representation of an enum map for type `V`, usually an array.
    type Array;
    /// Number of possible states the type can have.
    const POSSIBLE_VALUES: usize;
    /// Gets a slice from an array type.
    fn slice(array: &Self::Array) -> &[V];
    /// Gets a mutable slice from an array type.
    fn slice_mut(array: &mut Self::Array) -> &mut [V];
    /// Takes an usize, and returns an element matching `to_usize` function.
    fn from_usize(value: usize) -> Self;
    /// Returns an unique identifier for a value within range of `0..POSSIBLE_VALUES`.
    fn to_usize(self) -> usize;
    /// Creates an array using a function called for each argument.
    fn from_function<F: FnMut(Self) -> V>(f: F) -> Self::Array;
}

impl<T> Enum<T> for bool {
    type Array = [T; 2];
    const POSSIBLE_VALUES: usize = 2;
    #[inline]
    fn slice(array: &[T; 2]) -> &[T] {
        array
    }
    #[inline]
    fn slice_mut(array: &mut [T; 2]) -> &mut [T] {
        array
    }
    #[inline]
    fn from_usize(value: usize) -> Self {
        match value {
            0 => false,
            1 => true,
            _ => unreachable!(),
        }
    }
    #[inline]
    fn to_usize(self) -> usize {
        self as usize
    }
    #[inline]
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 2] {
        [f(false), f(true)]
    }
}

impl<T> Enum<T> for u8 {
    type Array = [T; 256];
    const POSSIBLE_VALUES: usize = 256;
    #[inline]
    fn slice(array: &[T; 256]) -> &[T] {
        array
    }
    #[inline]
    fn slice_mut(array: &mut [T; 256]) -> &mut [T] {
        array
    }
    #[inline]
    fn from_usize(value: usize) -> Self {
        value as u8
    }
    #[inline]
    fn to_usize(self) -> usize {
        self as usize
    }
    #[inline]
    fn from_function<F: FnMut(Self) -> T>(mut f: F) -> [T; 256] {
        array![|i| f(i as u8); 256]
    }
}
<|endoftext|>


<commit_before>pub mod vcx;
pub mod connection;
pub mod issuer_credential;
pub mod utils;
pub mod proof;
pub mod credential_def;
pub mod schema;
pub mod credential;
pub mod disclosed_proof;
pub mod wallet;
pub mod logger;
pub mod return_types_u32;

use std::fmt;

/// This macro allows the VcxStateType to be
/// serialized within serde as an integer (represented as
/// a string, because its still JSON).
macro_rules! enum_number {
    ($name:ident { $($variant:ident = $value:expr, )* }) => {
        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
        pub enum $name {
            $($variant = $value,)*
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::Serializer
            {
                // Serialize the enum as a u64.
                serializer.serialize_u64(*self as u64)
            }
        }

        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer<'de>
            {
                struct Visitor;

                impl<'de> ::serde::de::Visitor<'de> for Visitor {
                    type Value = $name;

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("positive integer")
                    }

                    fn visit_u64<E>(self, value: u64) -> Result<$name, E>
                        where E: ::serde::de::Error
                    {
                        // Rust does not come with a simple way of converting a
                        // number to an enum, so use a big `match`.
                        match value {
                            $( $value => Ok($name::$variant), )*
                            _ => Err(E::custom(
                                format!("unknown {} value: {}",
                                stringify!($name), value))),
                        }
                    }
                }

                // Deserialize the enum from a u64.
                deserializer.deserialize_u64(Visitor)
            }
        }
    }
}

enum_number!(VcxStateType
{
    VcxStateNone = 0,
    VcxStateInitialized = 1,
    VcxStateOfferSent = 2,
    VcxStateRequestReceived = 3,
    VcxStateAccepted = 4,
    VcxStateUnfulfilled = 5,
    VcxStateExpired = 6,
    VcxStateRevoked = 7,
});

impl VcxStateType {
    pub fn from_u32(state: u32) -> VcxStateType {
        match state {
            0 => VcxStateType::VcxStateNone,
            1 => VcxStateType::VcxStateInitialized,
            2 => VcxStateType::VcxStateOfferSent,
            3 => VcxStateType::VcxStateRequestReceived,
            4 => VcxStateType::VcxStateAccepted,
            5 => VcxStateType::VcxStateUnfulfilled,
            6 => VcxStateType::VcxStateExpired,
            7 => VcxStateType::VcxStateRevoked,
            _ => VcxStateType::VcxStateNone,
        }
    }
}

// undefined is correlated with VcxStateNon -> Haven't received Proof
// Validated is both validated by indy-sdk and by comparing proof-request
// Invalid is that it failed one or both of validation processes
enum_number!(ProofStateType
{
    ProofUndefined = 0,
    ProofValidated = 1,
    ProofInvalid = 2,
});

enum_number!(PublicEntityStateType
{
    Built = 0,
    Published = 1,
});

impl Default for PublicEntityStateType{
    fn default() -> Self {
        PublicEntityStateType::Published
    }
}

#[repr(C)]
pub struct VcxStatus {
    pub handle: libc::c_int,
    pub status: libc::c_int,
    pub msg: *mut libc::c_char,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use self::VcxStateType::*;

    #[test]
    fn test_serialize_vcx_state_type(){
        let z = VcxStateNone;
        let y = serde_json::to_string(&z).unwrap();
        assert_eq!(y,"0");
    }
}
<commit_msg>Missing state types<commit_after>pub mod vcx;
pub mod connection;
pub mod issuer_credential;
pub mod utils;
pub mod proof;
pub mod credential_def;
pub mod schema;
pub mod credential;
pub mod disclosed_proof;
pub mod wallet;
pub mod logger;
pub mod return_types_u32;

use std::fmt;

/// This macro allows the VcxStateType to be
/// serialized within serde as an integer (represented as
/// a string, because its still JSON).
macro_rules! enum_number {
    ($name:ident { $($variant:ident = $value:expr, )* }) => {
        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
        pub enum $name {
            $($variant = $value,)*
        }

        impl ::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::Serializer
            {
                // Serialize the enum as a u64.
                serializer.serialize_u64(*self as u64)
            }
        }

        impl<'de> ::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::Deserializer<'de>
            {
                struct Visitor;

                impl<'de> ::serde::de::Visitor<'de> for Visitor {
                    type Value = $name;

                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("positive integer")
                    }

                    fn visit_u64<E>(self, value: u64) -> Result<$name, E>
                        where E: ::serde::de::Error
                    {
                        // Rust does not come with a simple way of converting a
                        // number to an enum, so use a big `match`.
                        match value {
                            $( $value => Ok($name::$variant), )*
                            _ => Err(E::custom(
                                format!("unknown {} value: {}",
                                stringify!($name), value))),
                        }
                    }
                }

                // Deserialize the enum from a u64.
                deserializer.deserialize_u64(Visitor)
            }
        }
    }
}

enum_number!(VcxStateType
{
    VcxStateNone = 0,
    VcxStateInitialized = 1,
    VcxStateOfferSent = 2,
    VcxStateRequestReceived = 3,
    VcxStateAccepted = 4,
    VcxStateUnfulfilled = 5,
    VcxStateExpired = 6,
    VcxStateRevoked = 7,
    VcxStateRedirected = 8,
    VcxStateRejected = 9,
});

impl VcxStateType {
    pub fn from_u32(state: u32) -> VcxStateType {
        match state {
            0 => VcxStateType::VcxStateNone,
            1 => VcxStateType::VcxStateInitialized,
            2 => VcxStateType::VcxStateOfferSent,
            3 => VcxStateType::VcxStateRequestReceived,
            4 => VcxStateType::VcxStateAccepted,
            5 => VcxStateType::VcxStateUnfulfilled,
            6 => VcxStateType::VcxStateExpired,
            7 => VcxStateType::VcxStateRevoked,
            _ => VcxStateType::VcxStateNone,
        }
    }
}

// undefined is correlated with VcxStateNon -> Haven't received Proof
// Validated is both validated by indy-sdk and by comparing proof-request
// Invalid is that it failed one or both of validation processes
enum_number!(ProofStateType
{
    ProofUndefined = 0,
    ProofValidated = 1,
    ProofInvalid = 2,
});

enum_number!(PublicEntityStateType
{
    Built = 0,
    Published = 1,
});

impl Default for PublicEntityStateType{
    fn default() -> Self {
        PublicEntityStateType::Published
    }
}

#[repr(C)]
pub struct VcxStatus {
    pub handle: libc::c_int,
    pub status: libc::c_int,
    pub msg: *mut libc::c_char,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use self::VcxStateType::*;

    #[test]
    fn test_serialize_vcx_state_type(){
        let z = VcxStateNone;
        let y = serde_json::to_string(&z).unwrap();
        assert_eq!(y,"0");
    }
}
<|endoftext|>


<commit_before>use self::verify_proposer_slashing::verify_proposer_slashing;
use crate::errors::{BlockInvalid as Invalid, BlockProcessingError as Error, IntoWithIndex};
use hashing::hash;
use log::debug;
use ssz::{ssz_encode, SignedRoot, TreeHash};
use types::*;

pub use self::verify_attester_slashing::verify_attester_slashing;
pub use validate_attestation::{validate_attestation, validate_attestation_without_signature};
pub use verify_deposit::verify_deposit;
pub use verify_exit::verify_exit;
pub use verify_transfer::verify_transfer;

mod validate_attestation;
mod verify_attester_slashing;
mod verify_deposit;
mod verify_exit;
mod verify_proposer_slashing;
mod verify_slashable_attestation;
mod verify_transfer;

/// Updates the state for a new block, whilst validating that the block is valid.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
pub fn per_block_processing(
    state: &mut BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    per_block_processing_signature_optional(state, block, true, spec)
}

/// Updates the state for a new block, whilst validating that the block is valid, without actually
/// checking the block proposer signature.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
pub fn per_block_processing_without_verifying_block_signature(
    state: &mut BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    per_block_processing_signature_optional(state, block, false, spec)
}

/// Updates the state for a new block, whilst validating that the block is valid, optionally
/// checking the block proposer signature.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
fn per_block_processing_signature_optional(
    mut state: &mut BeaconState,
    block: &BeaconBlock,
    should_verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    // Verify that `block.slot == state.slot`.
    verify!(block.slot == state.slot, Invalid::StateSlotMismatch);

    // Get the epoch for future ergonomics.
    let epoch = block.slot.epoch(spec.slots_per_epoch);

    // Ensure the current epoch cache is built.
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    // Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
    let block_proposer =
        &state.validator_registry[state.get_beacon_proposer_index(block.slot, spec)?];

    // Block signature
    if should_verify_block_signature {
        verify!(
            verify_block_signature(&block, &block_proposer, &state.fork, spec,),
            Invalid::BadSignature
        );
    }

    // Randao

    // Verify that `bls_verify(pubkey=proposer.pubkey,
    // message_hash=hash_tree_root(get_current_epoch(state)), signature=block.randao_reveal,
    // domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`.
    verify!(
        block.randao_reveal.verify(
            &state.current_epoch(spec).hash_tree_root()[..],
            spec.get_domain(epoch, Domain::Randao, &state.fork),
            &block_proposer.pubkey
        ),
        Invalid::BadRandaoSignature
    );

    // Update the state's RANDAO mix with the one revealed in the block.
    update_randao(&mut state, &block.randao_reveal, spec)?;

    // Eth1 Data

    // Either increment the eth1_data vote count, or add a new eth1_data.
    let matching_eth1_vote_index = state
        .eth1_data_votes
        .iter()
        .position(|vote| vote.eth1_data == block.eth1_data);
    if let Some(index) = matching_eth1_vote_index {
        state.eth1_data_votes[index].vote_count += 1;
    } else {
        state.eth1_data_votes.push(Eth1DataVote {
            eth1_data: block.eth1_data.clone(),
            vote_count: 1,
        });
    }

    //Proposer slashings

    verify!(
        block.body.proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Invalid::MaxProposerSlashingsExceeded
    );
    for (i, proposer_slashing) in block.body.proposer_slashings.iter().enumerate() {
        verify_proposer_slashing(proposer_slashing, &state, spec)
            .map_err(|e| e.into_with_index(i))?;
        state.slash_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    // Attester Slashings

    verify!(
        block.body.attester_slashings.len() as u64 <= spec.max_attester_slashings,
        Invalid::MaxAttesterSlashingsExceed
    );
    for (i, attester_slashing) in block.body.attester_slashings.iter().enumerate() {
        let slashable_indices = verify_attester_slashing(&state, &attester_slashing, spec)
            .map_err(|e| e.into_with_index(i))?;
        for i in slashable_indices {
            state.slash_validator(i as usize, spec)?;
        }
    }

    // Attestations

    verify!(
        block.body.attestations.len() as u64 <= spec.max_attestations,
        Invalid::MaxAttestationsExceeded
    );
    for (i, attestation) in block.body.attestations.iter().enumerate() {
        // Build the previous epoch cache only if required by an attestation.
        if attestation.data.slot.epoch(spec.slots_per_epoch) == state.previous_epoch(spec) {
            state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
        }

        validate_attestation(&mut state, attestation, spec).map_err(|e| e.into_with_index(i))?;

        let pending_attestation = PendingAttestation {
            data: attestation.data.clone(),
            aggregation_bitfield: attestation.aggregation_bitfield.clone(),
            custody_bitfield: attestation.custody_bitfield.clone(),
            inclusion_slot: state.slot,
        };
        state.latest_attestations.push(pending_attestation);
    }

    // Deposits

    verify!(
        block.body.deposits.len() as u64 <= spec.max_deposits,
        Invalid::MaxDepositsExceeded
    );
    for (i, deposit) in block.body.deposits.iter().enumerate() {
        verify_deposit(&mut state, deposit, spec).map_err(|e| e.into_with_index(i))?;

        state
            .process_deposit(
                deposit.deposit_data.deposit_input.pubkey.clone(),
                deposit.deposit_data.amount,
                deposit
                    .deposit_data
                    .deposit_input
                    .proof_of_possession
                    .clone(),
                deposit.deposit_data.deposit_input.withdrawal_credentials,
                None,
                spec,
            )
            .map_err(|_| Error::Invalid(Invalid::DepositProcessingFailed(i)))?;

        state.deposit_index += 1;
    }

    // Exits

    verify!(
        block.body.voluntary_exits.len() as u64 <= spec.max_voluntary_exits,
        Invalid::MaxExitsExceeded
    );
    for (i, exit) in block.body.voluntary_exits.iter().enumerate() {
        verify_exit(&state, exit, spec).map_err(|e| e.into_with_index(i))?;

        state.initiate_validator_exit(exit.validator_index as usize);
    }

    // Transfers
    verify!(
        block.body.transfers.len() as u64 <= spec.max_transfers,
        Invalid::MaxTransfersExceed
    );
    for (i, transfer) in block.body.transfers.iter().enumerate() {
        verify_transfer(&state, transfer, spec).map_err(|e| e.into_with_index(i))?;

        let block_proposer = state.get_beacon_proposer_index(state.slot, spec)?;

        state.validator_balances[transfer.from as usize] -= transfer.amount + transfer.fee;
        state.validator_balances[transfer.to as usize] += transfer.amount + transfer.fee;
        state.validator_balances[block_proposer as usize] += transfer.fee;
    }

    debug!("State transition complete.");

    Ok(())
}

/// Verifies the signature of a block.
///
/// Spec v0.4.0
pub fn verify_block_signature(
    block: &BeaconBlock,
    block_proposer: &Validator,
    fork: &Fork,
    spec: &ChainSpec,
) -> bool {
    // Let proposal = `Proposal(block.slot, BEACON_CHAIN_SHARD_NUMBER, signed_root(block,
    // "signature"), block.signature)`.
    let proposal = Proposal {
        slot: block.slot,
        shard: spec.beacon_chain_shard_number,
        block_root: Hash256::from(&block.signed_root()[..]),
        signature: block.signature.clone(),
    };
    let domain = spec.get_domain(
        block.slot.epoch(spec.slots_per_epoch),
        Domain::Proposal,
        fork,
    );
    // Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposal,
    // "signature"), signature=proposal.signature, domain=get_domain(state.fork,
    // get_current_epoch(state), DOMAIN_PROPOSAL))`.
    proposal
        .signature
        .verify(&proposal.signed_root()[..], domain, &block_proposer.pubkey)
}

/// Updates the present randao mix.
///
/// Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] =
/// xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`.
///
/// Spec v0.4.0
pub fn update_randao(
    state: &mut BeaconState,
    reveal: &Signature,
    spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
    let hashed_reveal = {
        let encoded_signature = ssz_encode(reveal);
        Hash256::from(&hash(&encoded_signature[..])[..])
    };

    let current_epoch = state.slot.epoch(spec.slots_per_epoch);

    let current_mix = state
        .get_randao_mix(current_epoch, spec)
        .ok_or_else(|| BeaconStateError::InsufficientRandaoMixes)?;

    let new_mix = *current_mix ^ hashed_reveal;

    let index = current_epoch.as_usize() % spec.latest_randao_mixes_length;

    if index < state.latest_randao_mixes.len() {
        state.latest_randao_mixes[index] = new_mix;
        Ok(())
    } else {
        Err(BeaconStateError::InsufficientRandaoMixes)
    }
}
<commit_msg>Break per-block-processing into smaller fns<commit_after>use self::verify_proposer_slashing::verify_proposer_slashing;
use crate::errors::{BlockInvalid as Invalid, BlockProcessingError as Error, IntoWithIndex};
use hashing::hash;
use log::debug;
use ssz::{ssz_encode, SignedRoot, TreeHash};
use types::*;

pub use self::verify_attester_slashing::verify_attester_slashing;
pub use validate_attestation::{validate_attestation, validate_attestation_without_signature};
pub use verify_deposit::verify_deposit;
pub use verify_exit::verify_exit;
pub use verify_transfer::verify_transfer;

mod validate_attestation;
mod verify_attester_slashing;
mod verify_deposit;
mod verify_exit;
mod verify_proposer_slashing;
mod verify_slashable_attestation;
mod verify_transfer;

/// Updates the state for a new block, whilst validating that the block is valid.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
pub fn per_block_processing(
    state: &mut BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    per_block_processing_signature_optional(state, block, true, spec)
}

/// Updates the state for a new block, whilst validating that the block is valid, without actually
/// checking the block proposer signature.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
pub fn per_block_processing_without_verifying_block_signature(
    state: &mut BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    per_block_processing_signature_optional(state, block, false, spec)
}

/// Updates the state for a new block, whilst validating that the block is valid, optionally
/// checking the block proposer signature.
///
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// Spec v0.4.0
fn per_block_processing_signature_optional(
    mut state: &mut BeaconState,
    block: &BeaconBlock,
    should_verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    // Verify that `block.slot == state.slot`.
    verify!(block.slot == state.slot, Invalid::StateSlotMismatch);

    // Ensure the current epoch cache is built.
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    if should_verify_block_signature {
        verify_block_signature(&state, &block, &spec)?;
    }
    process_randao(&mut state, &block, &spec)?;
    process_eth1_data(&mut state, &block.eth1_data)?;
    process_proposer_slashings(&mut state, &block.body.proposer_slashings[..], spec)?;
    process_attester_slashings(&mut state, &block.body.attester_slashings[..], spec)?;
    process_attestations(&mut state, &block.body.attestations[..], spec)?;
    process_deposits(&mut state, &block.body.deposits[..], spec)?;
    process_exits(&mut state, &block.body.voluntary_exits[..], spec)?;
    process_transfers(&mut state, &block.body.transfers[..], spec)?;

    debug!("per_block_processing complete.");

    Ok(())
}

/// Verifies the signature of a block.
///
/// Spec v0.4.0
pub fn verify_block_signature(
    state: &BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let block_proposer =
        &state.validator_registry[state.get_beacon_proposer_index(block.slot, spec)?];

    let proposal = Proposal {
        slot: block.slot,
        shard: spec.beacon_chain_shard_number,
        block_root: Hash256::from(&block.signed_root()[..]),
        signature: block.signature.clone(),
    };
    let domain = spec.get_domain(
        block.slot.epoch(spec.slots_per_epoch),
        Domain::Proposal,
        &state.fork,
    );

    verify!(
        proposal
            .signature
            .verify(&proposal.signed_root()[..], domain, &block_proposer.pubkey),
        Invalid::BadSignature
    );

    Ok(())
}

/// Verifies the `randao_reveal` against the block's proposer pubkey and updates
/// `state.latest_randao_mixes`.
///
/// Spec v0.4.0
pub fn process_randao(
    state: &mut BeaconState,
    block: &BeaconBlock,
    spec: &ChainSpec,
) -> Result<(), Error> {
    // Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
    let block_proposer =
        &state.validator_registry[state.get_beacon_proposer_index(block.slot, spec)?];

    // Verify that `bls_verify(pubkey=proposer.pubkey,
    // message_hash=hash_tree_root(get_current_epoch(state)), signature=block.randao_reveal,
    // domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`.
    verify!(
        block.randao_reveal.verify(
            &state.current_epoch(spec).hash_tree_root()[..],
            spec.get_domain(
                block.slot.epoch(spec.slots_per_epoch),
                Domain::Randao,
                &state.fork
            ),
            &block_proposer.pubkey
        ),
        Invalid::BadRandaoSignature
    );

    // Update the state's RANDAO mix with the one revealed in the block.
    update_randao(state, &block.randao_reveal, spec)?;

    Ok(())
}

/// Update the `state.eth1_data_votes` based upon the `eth1_data` provided.
///
/// Spec v0.4.0
pub fn process_eth1_data(state: &mut BeaconState, eth1_data: &Eth1Data) -> Result<(), Error> {
    // Either increment the eth1_data vote count, or add a new eth1_data.
    let matching_eth1_vote_index = state
        .eth1_data_votes
        .iter()
        .position(|vote| vote.eth1_data == *eth1_data);
    if let Some(index) = matching_eth1_vote_index {
        state.eth1_data_votes[index].vote_count += 1;
    } else {
        state.eth1_data_votes.push(Eth1DataVote {
            eth1_data: eth1_data.clone(),
            vote_count: 1,
        });
    }

    Ok(())
}

/// Updates the present randao mix.
///
/// Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] =
/// xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`.
///
/// Spec v0.4.0
pub fn update_randao(
    state: &mut BeaconState,
    reveal: &Signature,
    spec: &ChainSpec,
) -> Result<(), BeaconStateError> {
    let hashed_reveal = {
        let encoded_signature = ssz_encode(reveal);
        Hash256::from(&hash(&encoded_signature[..])[..])
    };

    let current_epoch = state.slot.epoch(spec.slots_per_epoch);

    let current_mix = state
        .get_randao_mix(current_epoch, spec)
        .ok_or_else(|| BeaconStateError::InsufficientRandaoMixes)?;

    let new_mix = *current_mix ^ hashed_reveal;

    let index = current_epoch.as_usize() % spec.latest_randao_mixes_length;

    if index < state.latest_randao_mixes.len() {
        state.latest_randao_mixes[index] = new_mix;
        Ok(())
    } else {
        Err(BeaconStateError::InsufficientRandaoMixes)
    }
}

/// Validates each `ProposerSlashing` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_proposer_slashings(
    state: &mut BeaconState,
    proposer_slashings: &[ProposerSlashing],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Invalid::MaxProposerSlashingsExceeded
    );
    for (i, proposer_slashing) in proposer_slashings.iter().enumerate() {
        verify_proposer_slashing(proposer_slashing, &state, spec)
            .map_err(|e| e.into_with_index(i))?;
        state.slash_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    Ok(())
}

/// Validates each `AttesterSlsashing` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_attester_slashings(
    state: &mut BeaconState,
    attester_slashings: &[AttesterSlashing],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        attester_slashings.len() as u64 <= spec.max_attester_slashings,
        Invalid::MaxAttesterSlashingsExceed
    );
    for (i, attester_slashing) in attester_slashings.iter().enumerate() {
        let slashable_indices = verify_attester_slashing(&state, &attester_slashing, spec)
            .map_err(|e| e.into_with_index(i))?;
        for i in slashable_indices {
            state.slash_validator(i as usize, spec)?;
        }
    }

    Ok(())
}

/// Validates each `Attestation` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_attestations(
    state: &mut BeaconState,
    attestations: &[Attestation],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        attestations.len() as u64 <= spec.max_attestations,
        Invalid::MaxAttestationsExceeded
    );
    for (i, attestation) in attestations.iter().enumerate() {
        // Build the previous epoch cache only if required by an attestation.
        if attestation.data.slot.epoch(spec.slots_per_epoch) == state.previous_epoch(spec) {
            state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
        }

        validate_attestation(state, attestation, spec).map_err(|e| e.into_with_index(i))?;

        let pending_attestation = PendingAttestation {
            data: attestation.data.clone(),
            aggregation_bitfield: attestation.aggregation_bitfield.clone(),
            custody_bitfield: attestation.custody_bitfield.clone(),
            inclusion_slot: state.slot,
        };
        state.latest_attestations.push(pending_attestation);
    }

    Ok(())
}

/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_deposits(
    state: &mut BeaconState,
    deposits: &[Deposit],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        deposits.len() as u64 <= spec.max_deposits,
        Invalid::MaxDepositsExceeded
    );
    for (i, deposit) in deposits.iter().enumerate() {
        verify_deposit(state, deposit, spec).map_err(|e| e.into_with_index(i))?;

        state
            .process_deposit(
                deposit.deposit_data.deposit_input.pubkey.clone(),
                deposit.deposit_data.amount,
                deposit
                    .deposit_data
                    .deposit_input
                    .proof_of_possession
                    .clone(),
                deposit.deposit_data.deposit_input.withdrawal_credentials,
                None,
                spec,
            )
            .map_err(|_| Error::Invalid(Invalid::DepositProcessingFailed(i)))?;

        state.deposit_index += 1;
    }

    Ok(())
}

/// Validates each `Exit` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_exits(
    state: &mut BeaconState,
    voluntary_exits: &[VoluntaryExit],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        voluntary_exits.len() as u64 <= spec.max_voluntary_exits,
        Invalid::MaxExitsExceeded
    );
    for (i, exit) in voluntary_exits.iter().enumerate() {
        verify_exit(&state, exit, spec).map_err(|e| e.into_with_index(i))?;

        state.initiate_validator_exit(exit.validator_index as usize);
    }

    Ok(())
}

/// Validates each `Transfer` and updates the state, short-circuiting on an invalid object.
///
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.4.0
pub fn process_transfers(
    state: &mut BeaconState,
    transfers: &[Transfer],
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify!(
        transfers.len() as u64 <= spec.max_transfers,
        Invalid::MaxTransfersExceed
    );
    for (i, transfer) in transfers.iter().enumerate() {
        verify_transfer(&state, transfer, spec).map_err(|e| e.into_with_index(i))?;

        let block_proposer = state.get_beacon_proposer_index(state.slot, spec)?;

        state.validator_balances[transfer.from as usize] -= transfer.amount + transfer.fee;
        state.validator_balances[transfer.to as usize] += transfer.amount + transfer.fee;
        state.validator_balances[block_proposer as usize] += transfer.fee;
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! calculate cyclomatic complexity and warn about overly complex functions

use rustc::lint::*;
use rustc::middle::cfg::CFG;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::{Visitor, walk_expr};
use syntax::ast::Attribute;
use syntax::attr::*;
use syntax::codemap::Span;

use utils::{in_macro, LimitStack, span_help_and_lint};

/// **What it does:** This lint checks for methods with high cyclomatic complexity
///
/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better.
///
/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity
///
/// **Example:** No. You'll see it when you get the warning.
declare_lint! {
    pub CYCLOMATIC_COMPLEXITY, Warn,
    "finds functions that should be split up into multiple functions"
}

pub struct CyclomaticComplexity {
    limit: LimitStack,
}

impl CyclomaticComplexity {
    pub fn new(limit: u64) -> Self {
        CyclomaticComplexity { limit: LimitStack::new(limit) }
    }
}

impl LintPass for CyclomaticComplexity {
    fn get_lints(&self) -> LintArray {
        lint_array!(CYCLOMATIC_COMPLEXITY)
    }
}

impl CyclomaticComplexity {
    fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) {
        if in_macro(cx, span) {
            return;
        }
        let cfg = CFG::new(cx.tcx, block);
        let n = cfg.graph.len_nodes() as u64;
        let e = cfg.graph.len_edges() as u64;
        let cc = e + 2 - n;
        let mut arm_counter = MatchArmCounter(0);
        arm_counter.visit_block(block);
        let narms = arm_counter.0;

        let mut diverge_counter = DivergenceCounter(0, &cx.tcx);
        diverge_counter.visit_block(block);
        let divergence = diverge_counter.0;

        if cc + divergence < narms {
            report_cc_bug(cx, cc, narms, divergence, span);
        } else {
            let rust_cc = cc + divergence - narms;
            if rust_cc > self.limit.limit() {
                span_help_and_lint(cx,
                                   CYCLOMATIC_COMPLEXITY,
                                   span,
                                   &format!("the function has a cyclomatic complexity of {}", rust_cc),
                                   "you could split it up into multiple smaller functions");
            }
        }
    }
}

impl LateLintPass for CyclomaticComplexity {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(_, _, _, _, _, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let ImplItemKind::Method(_, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(_, Some(ref block)) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
    fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
}

struct MatchArmCounter(u64);

impl<'a> Visitor<'a> for MatchArmCounter {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprMatch(_, ref arms, _) => {
                walk_expr(self, e);
                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
                if arms_n > 1 {
                    self.0 += arms_n - 2;
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

struct DivergenceCounter<'a, 'tcx: 'a>(u64, &'a ty::TyCtxt<'tcx>);

impl<'a, 'b, 'tcx> Visitor<'a> for DivergenceCounter<'b, 'tcx> {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprCall(ref callee, _) => {
                walk_expr(self, e);
                let ty = self.1.node_id_to_type(callee.id);
                if let ty::TyBareFn(_, ty) = ty.sty {
                    if ty.sig.skip_binder().output.diverges() {
                        self.0 += 1;
                    }
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

#[cfg(feature="debugging")]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    cx.sess().span_bug(span,
                       &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
                                 div = {}. Please file a bug report.",
                                cc,
                                narms,
                                div));;
}
#[cfg(not(feature="debugging"))]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow {
        cx.sess().span_note_without_error(span,
                                          &format!("Clippy encountered a bug calculating cyclomatic complexity \
                                                    (hide this message with `#[allow(cyclomatic_complexity)]`): cc \
                                                    = {}, arms = {}, div = {}. Please file a bug report.",
                                                   cc,
                                                   narms,
                                                   div));
    }
}
<commit_msg>simplify cyclomatic complexity auxiliarly value computation<commit_after>//! calculate cyclomatic complexity and warn about overly complex functions

use rustc::lint::*;
use rustc::middle::cfg::CFG;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::{Visitor, walk_expr};
use syntax::ast::Attribute;
use syntax::attr::*;
use syntax::codemap::Span;

use utils::{in_macro, LimitStack, span_help_and_lint};

/// **What it does:** This lint checks for methods with high cyclomatic complexity
///
/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly readable. Also LLVM will usually optimize small methods better.
///
/// **Known problems:** Sometimes it's hard to find a way to reduce the complexity
///
/// **Example:** No. You'll see it when you get the warning.
declare_lint! {
    pub CYCLOMATIC_COMPLEXITY, Warn,
    "finds functions that should be split up into multiple functions"
}

pub struct CyclomaticComplexity {
    limit: LimitStack,
}

impl CyclomaticComplexity {
    pub fn new(limit: u64) -> Self {
        CyclomaticComplexity { limit: LimitStack::new(limit) }
    }
}

impl LintPass for CyclomaticComplexity {
    fn get_lints(&self) -> LintArray {
        lint_array!(CYCLOMATIC_COMPLEXITY)
    }
}

impl CyclomaticComplexity {
    fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, block: &Block, span: Span) {
        if in_macro(cx, span) {
            return;
        }
        let cfg = CFG::new(cx.tcx, block);
        let n = cfg.graph.len_nodes() as u64;
        let e = cfg.graph.len_edges() as u64;
        let cc = e + 2 - n;
        let mut helper = CCHelper {
            match_arms: 0,
            divergence: 0,
            tcx: &cx.tcx,
        };
        helper.visit_block(block);
        let CCHelper {
            match_arms,
            divergence,
            ..
        } = helper;

        if cc + divergence < match_arms {
            report_cc_bug(cx, cc, match_arms, divergence, span);
        } else {
            let rust_cc = cc + divergence - match_arms;
            if rust_cc > self.limit.limit() {
                span_help_and_lint(cx,
                                   CYCLOMATIC_COMPLEXITY,
                                   span,
                                   &format!("the function has a cyclomatic complexity of {}", rust_cc),
                                   "you could split it up into multiple smaller functions");
            }
        }
    }
}

impl LateLintPass for CyclomaticComplexity {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(_, _, _, _, _, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let ImplItemKind::Method(_, ref block) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(_, Some(ref block)) = item.node {
            self.check(cx, block, item.span);
        }
    }

    fn enter_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
    fn exit_lint_attrs(&mut self, cx: &LateContext, attrs: &[Attribute]) {
        self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
    }
}

struct CCHelper<'a, 'tcx: 'a> {
    match_arms: u64,
    divergence: u64,
    tcx: &'a ty::TyCtxt<'tcx>,
}

impl<'a, 'b, 'tcx> Visitor<'a> for CCHelper<'b, 'tcx> {
    fn visit_expr(&mut self, e: &'a Expr) {
        match e.node {
            ExprMatch(_, ref arms, _) => {
                walk_expr(self, e);
                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
                if arms_n > 1 {
                    self.match_arms += arms_n - 2;
                }
            }
            ExprCall(ref callee, _) => {
                walk_expr(self, e);
                let ty = self.tcx.node_id_to_type(callee.id);
                if let ty::TyBareFn(_, ty) = ty.sty {
                    if ty.sig.skip_binder().output.diverges() {
                        self.divergence += 1;
                    }
                }
            }
            ExprClosure(..) => {}
            _ => walk_expr(self, e),
        }
    }
}

#[cfg(feature="debugging")]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    cx.sess().span_bug(span,
                       &format!("Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
                                 div = {}. Please file a bug report.",
                                cc,
                                narms,
                                div));;
}
#[cfg(not(feature="debugging"))]
fn report_cc_bug(cx: &LateContext, cc: u64, narms: u64, div: u64, span: Span) {
    if cx.current_level(CYCLOMATIC_COMPLEXITY) != Level::Allow {
        cx.sess().span_note_without_error(span,
                                          &format!("Clippy encountered a bug calculating cyclomatic complexity \
                                                    (hide this message with `#[allow(cyclomatic_complexity)]`): cc \
                                                    = {}, arms = {}, div = {}. Please file a bug report.",
                                                   cc,
                                                   narms,
                                                   div));
    }
}
<|endoftext|>


<commit_before>//! This is copied almost directly from the `futures` crate [1]. The difference is this
//! implmentation uses the `AsyncRead` and `AsyncWrite` traits from the `tokio` ecosystem. Once
//! these traits become part of the standard library the need to duplicate the functionality here
//! will be obsolete.
//!
//! [1] https://github.com/rust-lang/futures-rs/blob/e76780341234cda6e77edec7ece83559bbcd0162/futures-util/src/io/allow_std.rs#L1

use futures::{io::{IoSlice,
                   IoSliceMut,
                   SeekFrom},
              task::{Context,
                     Poll}};
use std::{fmt,
          io,
          pin::Pin};
use tokio::io::{AsyncBufRead,
                AsyncRead,
                AsyncWrite};

/// A simple wrapper type which allows types which implement only
/// implement `std::io::Read` or `std::io::Write`
/// to be used in contexts which expect an `AsyncRead` or `AsyncWrite`.
///
/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`,
/// it is expected that they will notify the current task on readiness.
/// Synchronous `std` types should not issue errors of this kind and
/// are safe to use in this context. However, using these types with
/// `AllowStdIo` will cause the event loop to block, so they should be used
/// with care.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AllowStdIo<T>(T);

impl<T> Unpin for AllowStdIo<T> {}

macro_rules! try_with_interrupt {
    ($e:expr) => {
        loop {
            match $e {
                Ok(e) => {
                    break e;
                }
                Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => {
                    continue;
                }
                Err(e) => {
                    return Poll::Ready(Err(e));
                }
            }
        }
    };
}

#[allow(unused)]
impl<T> AllowStdIo<T> {
    /// Creates a new `AllowStdIo` from an existing IO object.
    pub fn new(io: T) -> Self { AllowStdIo(io) }

    /// Returns a reference to the contained IO object.
    pub fn get_ref(&self) -> &T { &self.0 }

    /// Returns a mutable reference to the contained IO object.
    pub fn get_mut(&mut self) -> &mut T { &mut self.0 }

    /// Consumes self and returns the contained IO object.
    pub fn into_inner(self) -> T { self.0 }
}

impl<T> io::Write for AllowStdIo<T> where T: io::Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.0.write_vectored(bufs)
    }

    fn flush(&mut self) -> io::Result<()> { self.0.flush() }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.0.write_all(buf) }

    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.0.write_fmt(fmt) }
}

impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write
{
    fn poll_write(mut self: Pin<&mut Self>,
                  _: &mut Context<'_>,
                  buf: &[u8])
                  -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(try_with_interrupt!(self.0.write(buf))))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        try_with_interrupt!(self.0.flush());
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl<T> io::Read for AllowStdIo<T> where T: io::Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }

    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.0.read_vectored(bufs)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { self.0.read_to_end(buf) }

    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.0.read_exact(buf) }
}

impl<T> AsyncRead for AllowStdIo<T> where T: io::Read
{
    fn poll_read(mut self: Pin<&mut Self>,
                 _: &mut Context<'_>,
                 buf: &mut [u8])
                 -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(try_with_interrupt!(self.0.read(buf))))
    }
}

impl<T> io::Seek for AllowStdIo<T> where T: io::Seek
{
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.0.seek(pos) }
}

impl<T> io::BufRead for AllowStdIo<T> where T: io::BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> { self.0.fill_buf() }

    fn consume(&mut self, amt: usize) { self.0.consume(amt) }
}

impl<T> AsyncBufRead for AllowStdIo<T> where T: io::BufRead
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        let this: *mut Self = &mut *self as *mut _;
        Poll::Ready(Ok(try_with_interrupt!(unsafe { &mut *this }.0.fill_buf())))
    }

    fn consume(mut self: Pin<&mut Self>, amt: usize) { self.0.consume(amt) }
}
<commit_msg>Add link to issue in allow_std_io<commit_after>//! This is copied almost directly from the `futures` crate [1]. The difference is this
//! implmentation uses the `AsyncRead` and `AsyncWrite` traits from the `tokio` ecosystem. Once
//! these traits become part of the standard library the need to duplicate the functionality here
//! will be obsolete [2].
//!
//! [1] https://github.com/rust-lang/futures-rs/blob/e76780341234cda6e77edec7ece83559bbcd0162/futures-util/src/io/allow_std.rs#L1
//! [2] https://github.com/habitat-sh/habitat/issues/7414

use futures::{io::{IoSlice,
                   IoSliceMut,
                   SeekFrom},
              task::{Context,
                     Poll}};
use std::{fmt,
          io,
          pin::Pin};
use tokio::io::{AsyncBufRead,
                AsyncRead,
                AsyncWrite};

/// A simple wrapper type which allows types which implement only
/// implement `std::io::Read` or `std::io::Write`
/// to be used in contexts which expect an `AsyncRead` or `AsyncWrite`.
///
/// If these types issue an error with the kind `io::ErrorKind::WouldBlock`,
/// it is expected that they will notify the current task on readiness.
/// Synchronous `std` types should not issue errors of this kind and
/// are safe to use in this context. However, using these types with
/// `AllowStdIo` will cause the event loop to block, so they should be used
/// with care.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AllowStdIo<T>(T);

impl<T> Unpin for AllowStdIo<T> {}

macro_rules! try_with_interrupt {
    ($e:expr) => {
        loop {
            match $e {
                Ok(e) => {
                    break e;
                }
                Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => {
                    continue;
                }
                Err(e) => {
                    return Poll::Ready(Err(e));
                }
            }
        }
    };
}

#[allow(unused)]
impl<T> AllowStdIo<T> {
    /// Creates a new `AllowStdIo` from an existing IO object.
    pub fn new(io: T) -> Self { AllowStdIo(io) }

    /// Returns a reference to the contained IO object.
    pub fn get_ref(&self) -> &T { &self.0 }

    /// Returns a mutable reference to the contained IO object.
    pub fn get_mut(&mut self) -> &mut T { &mut self.0 }

    /// Consumes self and returns the contained IO object.
    pub fn into_inner(self) -> T { self.0 }
}

impl<T> io::Write for AllowStdIo<T> where T: io::Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }

    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.0.write_vectored(bufs)
    }

    fn flush(&mut self) -> io::Result<()> { self.0.flush() }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.0.write_all(buf) }

    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { self.0.write_fmt(fmt) }
}

impl<T> AsyncWrite for AllowStdIo<T> where T: io::Write
{
    fn poll_write(mut self: Pin<&mut Self>,
                  _: &mut Context<'_>,
                  buf: &[u8])
                  -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(try_with_interrupt!(self.0.write(buf))))
    }

    fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        try_with_interrupt!(self.0.flush());
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.poll_flush(cx)
    }
}

impl<T> io::Read for AllowStdIo<T> where T: io::Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }

    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.0.read_vectored(bufs)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { self.0.read_to_end(buf) }

    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { self.0.read_exact(buf) }
}

impl<T> AsyncRead for AllowStdIo<T> where T: io::Read
{
    fn poll_read(mut self: Pin<&mut Self>,
                 _: &mut Context<'_>,
                 buf: &mut [u8])
                 -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(try_with_interrupt!(self.0.read(buf))))
    }
}

impl<T> io::Seek for AllowStdIo<T> where T: io::Seek
{
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.0.seek(pos) }
}

impl<T> io::BufRead for AllowStdIo<T> where T: io::BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> { self.0.fill_buf() }

    fn consume(&mut self, amt: usize) { self.0.consume(amt) }
}

impl<T> AsyncBufRead for AllowStdIo<T> where T: io::BufRead
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        let this: *mut Self = &mut *self as *mut _;
        Poll::Ready(Ok(try_with_interrupt!(unsafe { &mut *this }.0.fill_buf())))
    }

    fn consume(mut self: Pin<&mut Self>, amt: usize) { self.0.consume(amt) }
}
<|endoftext|>


<commit_before>use prodbg_api::view::CViewCallbacks;
use libc::{c_void, c_uchar};
use std::rc::Rc;
use plugin::Plugin;
use plugins::PluginHandler;
use dynamic_reload::Lib;
use std::ptr;
use prodbg_api::ui::Ui;

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ViewHandle(pub usize);

pub struct ViewInstance {
    pub plugin_data: *mut c_void,
    pub ui: Ui,
    pub handle: ViewHandle,
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    pub plugin_type: Rc<Plugin>,
}

#[derive(Clone)]
struct ReloadState {
    name: String,
    ui: Ui,
    handle: ViewHandle,
}

pub struct ViewPlugins {
    pub instances: Vec<ViewInstance>,
    plugin_types: Vec<Rc<Plugin>>,
    reload_state: Vec<ReloadState>,
    handle_counter: ViewHandle,
}

impl PluginHandler for ViewPlugins {
    fn is_correct_plugin_type(&self, plugin: &Plugin) -> bool {
        plugin.type_name.contains("View")
    }

    fn add_plugin(&mut self, plugin: &Rc<Plugin>) {
        println!("added plugin type {}", plugin.type_name);
        self.plugin_types.push(plugin.clone())
    }

    fn unload_plugin(&mut self, lib: &Rc<Lib>) {
        self.reload_state.clear();
        for i in (0..self.instances.len()).rev() {
            if &self.instances[i].plugin_type.lib == lib {
                let state = ReloadState {
                    ui: self.instances[i].ui,
                    name: self.instances[i].plugin_type.name.clone(),
                    handle: self.instances[i].handle,
                };

                self.reload_state.push(state);
                self.instances.swap_remove(i);
            }
        }

        for i in (0..self.plugin_types.len()).rev() {
            if &self.plugin_types[i].lib == lib {
                self.plugin_types.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self) {
        let t = self.reload_state.clone();
        for reload_plugin in &t {
            Self::create_instance(self, reload_plugin.ui, &reload_plugin.name);
        }
    }

    fn reload_failed(&mut self) {}
}

impl ViewPlugins {
    pub fn new() -> ViewPlugins {
        ViewPlugins {
            instances: Vec::new(),
            plugin_types: Vec::new(),
            reload_state: Vec::new(),
            handle_counter: ViewHandle(0),
        }
    }

    pub extern "C" fn service_fun(_name: *const c_uchar) -> *mut c_void {
        ptr::null_mut()
    }

    pub fn get_view(&mut self, view_handle: ViewHandle) -> Option<&mut ViewInstance> {
        for i in 0..self.instances.len() {
            if self.instances[i].handle == view_handle {
                return Some(&mut self.instances[i]);
            }
        }

        None
    }

    pub fn create_instance_from_index(&mut self, ui: Ui, index: usize) -> Option<ViewHandle> {
        let plugin_data = unsafe {
            let callbacks = self.plugin_types[index].plugin_funcs as *mut CViewCallbacks;
            (*callbacks).create_instance.unwrap()(ptr::null(), Self::service_fun)
        };

        let handle = self.handle_counter;

        let instance = ViewInstance {
            plugin_data: plugin_data,
            ui: ui,
            handle: handle,
            x: 0.0,
            y: 0.0,
            width: 0.0,
            height: 0.0,
            plugin_type: self.plugin_types[index].clone(),
        };

        self.handle_counter.0 += 1;
        self.instances.push(instance);

        Some(handle)
    }

    pub fn create_instance(&mut self, ui: Ui, plugin_type: &String) -> Option<ViewHandle> {
        for i in 0..self.plugin_types.len() {
            if self.plugin_types[i].name != *plugin_type {
                continue;
            }

            return Self::create_instance_from_index(self, ui, i);
        }

        None
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_search_paths_none() {
        assert_eq!(1);
    }
}

<commit_msg>Fixed broken assert check<commit_after>use prodbg_api::view::CViewCallbacks;
use libc::{c_void, c_uchar};
use std::rc::Rc;
use plugin::Plugin;
use plugins::PluginHandler;
use dynamic_reload::Lib;
use std::ptr;
use prodbg_api::ui::Ui;

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ViewHandle(pub usize);

pub struct ViewInstance {
    pub plugin_data: *mut c_void,
    pub ui: Ui,
    pub handle: ViewHandle,
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    pub plugin_type: Rc<Plugin>,
}

#[derive(Clone)]
struct ReloadState {
    name: String,
    ui: Ui,
    handle: ViewHandle,
}

pub struct ViewPlugins {
    pub instances: Vec<ViewInstance>,
    plugin_types: Vec<Rc<Plugin>>,
    reload_state: Vec<ReloadState>,
    handle_counter: ViewHandle,
}

impl PluginHandler for ViewPlugins {
    fn is_correct_plugin_type(&self, plugin: &Plugin) -> bool {
        plugin.type_name.contains("View")
    }

    fn add_plugin(&mut self, plugin: &Rc<Plugin>) {
        println!("added plugin type {}", plugin.type_name);
        self.plugin_types.push(plugin.clone())
    }

    fn unload_plugin(&mut self, lib: &Rc<Lib>) {
        self.reload_state.clear();
        for i in (0..self.instances.len()).rev() {
            if &self.instances[i].plugin_type.lib == lib {
                let state = ReloadState {
                    ui: self.instances[i].ui,
                    name: self.instances[i].plugin_type.name.clone(),
                    handle: self.instances[i].handle,
                };

                self.reload_state.push(state);
                self.instances.swap_remove(i);
            }
        }

        for i in (0..self.plugin_types.len()).rev() {
            if &self.plugin_types[i].lib == lib {
                self.plugin_types.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self) {
        let t = self.reload_state.clone();
        for reload_plugin in &t {
            Self::create_instance(self, reload_plugin.ui, &reload_plugin.name);
        }
    }

    fn reload_failed(&mut self) {}
}

impl ViewPlugins {
    pub fn new() -> ViewPlugins {
        ViewPlugins {
            instances: Vec::new(),
            plugin_types: Vec::new(),
            reload_state: Vec::new(),
            handle_counter: ViewHandle(0),
        }
    }

    pub extern "C" fn service_fun(_name: *const c_uchar) -> *mut c_void {
        ptr::null_mut()
    }

    pub fn get_view(&mut self, view_handle: ViewHandle) -> Option<&mut ViewInstance> {
        for i in 0..self.instances.len() {
            if self.instances[i].handle == view_handle {
                return Some(&mut self.instances[i]);
            }
        }

        None
    }

    pub fn create_instance_from_index(&mut self, ui: Ui, index: usize) -> Option<ViewHandle> {
        let plugin_data = unsafe {
            let callbacks = self.plugin_types[index].plugin_funcs as *mut CViewCallbacks;
            (*callbacks).create_instance.unwrap()(ptr::null(), Self::service_fun)
        };

        let handle = self.handle_counter;

        let instance = ViewInstance {
            plugin_data: plugin_data,
            ui: ui,
            handle: handle,
            x: 0.0,
            y: 0.0,
            width: 0.0,
            height: 0.0,
            plugin_type: self.plugin_types[index].clone(),
        };

        self.handle_counter.0 += 1;
        self.instances.push(instance);

        Some(handle)
    }

    pub fn create_instance(&mut self, ui: Ui, plugin_type: &String) -> Option<ViewHandle> {
        for i in 0..self.plugin_types.len() {
            if self.plugin_types[i].name != *plugin_type {
                continue;
            }

            return Self::create_instance_from_index(self, ui, i);
        }

        None
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_search_paths_none() {
    }
}

<|endoftext|>