<commit_before>use expression::{AsExpression, Expression};
use super::operators::*;
use types::{Array, Text};

pub trait PgExpressionMethods: Expression + Sized {
    /// Creates a PostgreSQL `IS NOT DISTINCT FROM` expression. This behaves
    /// identically to the `=` operator, except that `NULL` is treated as a
    /// normal value.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
    /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
    /// assert_eq!(Ok(2), distinct.first(&connection));
    /// assert_eq!(Ok(1), not_distinct.first(&connection));
    /// # }
    /// ```
    fn is_not_distinct_from<T>(self, other: T) -> IsNotDistinctFrom<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsNotDistinctFrom::new(self, other.as_expression())
    }

    /// Creates a PostgreSQL `IS DISTINCT FROM` expression. This behaves
    /// identically to the `!=` operator, except that `NULL` is treated as a
    /// normal value.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
    /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
    /// assert_eq!(Ok(2), distinct.first(&connection));
    /// assert_eq!(Ok(1), not_distinct.first(&connection));
    /// # }
    /// ```
    fn is_distinct_from<T>(self, other: T) -> IsDistinctFrom<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsDistinctFrom::new(self, other.as_expression())
    }
}

impl<T: Expression> PgExpressionMethods for T {}

use super::date_and_time::{AtTimeZone, DateTimeLike};
use types::VarChar;

#[doc(hidden)]
pub trait PgTimestampExpressionMethods: Expression + Sized {
    /// Returns a PostgreSQL "AT TIME ZONE" expression
    fn at_time_zone<T>(self, timezone: T) -> AtTimeZone<Self, T::Expression>
    where
        T: AsExpression<VarChar>,
    {
        AtTimeZone::new(self, timezone.as_expression())
    }
}

impl<T: Expression> PgTimestampExpressionMethods for T
where
    T::SqlType: DateTimeLike,
{
}

pub trait ArrayExpressionMethods<ST>: Expression<SqlType = Array<ST>> + Sized {
    /// Compares two arrays for common elements, using the `&&` operator in
    /// the final SQL
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///         NewPost { tags: vec!["awesome", "great"] },
    ///         NewPost { tags: vec!["cool", "great"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["horrid", "cool"]));
    /// assert_eq!(Ok(vec![1, 3]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["cool", "great"]));
    /// assert_eq!(Ok(vec![1, 2, 3]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["horrid"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn overlaps_with<T>(self, other: T) -> OverlapsWith<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        OverlapsWith::new(self, other.as_expression())
    }

    /// Compares whether an array contains another array, using the `@>` operator.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.contains(vec!["cool"]));
    /// assert_eq!(Ok(vec![1]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.contains(vec!["cool", "amazing"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn contains<T>(self, other: T) -> Contains<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        Contains::new(self, other.as_expression())
    }

    /// Compares whether an array is contained by another array, using the `<@` operator.
    /// This is the opposite of `contains`
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.is_contained_by(vec!["cool", "awesome", "amazing"]));
    /// assert_eq!(Ok(vec![1]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.is_contained_by(vec!["cool"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn is_contained_by<T>(self, other: T) -> IsContainedBy<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsContainedBy::new(self, other.as_expression())
    }
}

impl<T, ST> ArrayExpressionMethods<ST> for T
where
    T: Expression<SqlType = Array<ST>>,
{
}

use expression::operators::{Asc, Desc};

pub trait SortExpressionMethods: Sized {
    /// Specify that nulls should come before other values in this ordering.
    /// Normally, nulls come last when sorting in ascending order and first
    /// when sorting in descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # table! {
    /// #     foos {
    /// #         id -> Integer,
    /// #         foo -> Nullable<Integer>,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     let connection = connection_no_data();
    /// #     connection.execute("DROP TABLE IF EXISTS foos").unwrap();
    /// connection.execute("CREATE TABLE foos (id SERIAL PRIMARY KEY, foo INTEGER)").unwrap();
    /// connection.execute("INSERT INTO foos (foo) VALUES (NULL), (1), (2)").unwrap();
    ///
    /// #     use self::foos::dsl::*;
    /// assert_eq!(Ok(vec![Some(1), Some(2), None]),
    ///            foos.select(foo).order(foo.asc()).load(&connection));
    /// assert_eq!(Ok(vec![None, Some(1), Some(2)]),
    ///            foos.select(foo).order(foo.asc().nulls_first()).load(&connection));
    /// #     connection.execute("DROP TABLE foos").unwrap();
    /// # }
    /// ```
    fn nulls_first(self) -> NullsFirst<Self> {
        NullsFirst::new(self)
    }

    /// Specify that nulls should come after other values in this ordering.
    /// Normally, nulls come last when sorting in ascending order and first
    /// when sorting in descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # table! {
    /// #     foos {
    /// #         id -> Integer,
    /// #         foo -> Nullable<Integer>,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     let connection = connection_no_data();
    /// #     connection.execute("DROP TABLE IF EXISTS foos").unwrap();
    /// connection.execute("CREATE TABLE foos (id SERIAL PRIMARY KEY, foo INTEGER)").unwrap();
    /// connection.execute("INSERT INTO foos (foo) VALUES (NULL), (1), (2)").unwrap();
    ///
    /// #     use self::foos::dsl::*;
    /// assert_eq!(Ok(vec![None, Some(2), Some(1)]),
    ///            foos.select(foo).order(foo.desc()).load(&connection));
    /// assert_eq!(Ok(vec![Some(2), Some(1), None]),
    ///            foos.select(foo).order(foo.desc().nulls_last()).load(&connection));
    /// #     connection.execute("DROP TABLE foos").unwrap();
    /// # }
    /// ```
    fn nulls_last(self) -> NullsLast<Self> {
        NullsLast::new(self)
    }
}

impl<T> SortExpressionMethods for Asc<T> {}

impl<T> SortExpressionMethods for Desc<T> {}

pub trait PgTextExpressionMethods: Expression<SqlType = Text> + Sized {
    /// Returns a SQL `ILIKE` expression
    fn ilike<T: AsExpression<Text>>(self, other: T) -> ILike<Self, T::Expression> {
        ILike::new(self.as_expression(), other.as_expression())
    }

    /// Returns a SQL `NOT ILIKE` expression
    fn not_ilike<T: AsExpression<Text>>(self, other: T) -> NotILike<Self, T::Expression> {
        NotILike::new(self.as_expression(), other.as_expression())
    }
}

impl<T: Expression<SqlType = Text>> PgTextExpressionMethods for T {}
<commit_msg>Document all of the PG expression method traits<commit_after>use expression::{AsExpression, Expression};
use super::operators::*;
use types::{Array, Text};

/// PostgreSQL expression methods which are not type specific.
///
/// This trait is implemented for all types that implement `Expression`.
pub trait PgExpressionMethods: Expression + Sized {
    /// Creates a PostgreSQL `IS NOT DISTINCT FROM` expression. This behaves
    /// identically to the `=` operator, except that `NULL` is treated as a
    /// normal value.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
    /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
    /// assert_eq!(Ok(2), distinct.first(&connection));
    /// assert_eq!(Ok(1), not_distinct.first(&connection));
    /// # }
    /// ```
    fn is_not_distinct_from<T>(self, other: T) -> IsNotDistinctFrom<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsNotDistinctFrom::new(self, other.as_expression())
    }

    /// Creates a PostgreSQL `IS DISTINCT FROM` expression. This behaves
    /// identically to the `!=` operator, except that `NULL` is treated as a
    /// normal value.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use self::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
    /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
    /// assert_eq!(Ok(2), distinct.first(&connection));
    /// assert_eq!(Ok(1), not_distinct.first(&connection));
    /// # }
    /// ```
    fn is_distinct_from<T>(self, other: T) -> IsDistinctFrom<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsDistinctFrom::new(self, other.as_expression())
    }
}

impl<T: Expression> PgExpressionMethods for T {}

use super::date_and_time::{AtTimeZone, DateTimeLike};
use types::VarChar;

/// PostgreSQL expression methods related to timestamps.
///
/// This trait is implemented for all types that implement `Expression` where
/// the `SqlType` is either `Timestamp` or `Timestamptz`
pub trait PgTimestampExpressionMethods: Expression + Sized {
    /// Returns a PostgreSQL "AT TIME ZONE" expression
    fn at_time_zone<T>(self, timezone: T) -> AtTimeZone<Self, T::Expression>
    where
        T: AsExpression<VarChar>,
    {
        AtTimeZone::new(self, timezone.as_expression())
    }
}

impl<T: Expression> PgTimestampExpressionMethods for T
where
    T::SqlType: DateTimeLike,
{
}

/// PostgreSQL expression methods related to arrays.
///
/// This trait is implemented for all types that implement `Expression` where
/// the `SqlType` is `Array`.
pub trait ArrayExpressionMethods<ST>: Expression<SqlType = Array<ST>> + Sized {
    /// Compares two arrays for common elements, using the `&&` operator in
    /// the final SQL
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///         NewPost { tags: vec!["awesome", "great"] },
    ///         NewPost { tags: vec!["cool", "great"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["horrid", "cool"]));
    /// assert_eq!(Ok(vec![1, 3]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["cool", "great"]));
    /// assert_eq!(Ok(vec![1, 2, 3]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.overlaps_with(vec!["horrid"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn overlaps_with<T>(self, other: T) -> OverlapsWith<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        OverlapsWith::new(self, other.as_expression())
    }

    /// Compares whether an array contains another array, using the `@>` operator.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.contains(vec!["cool"]));
    /// assert_eq!(Ok(vec![1]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.contains(vec!["cool", "amazing"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn contains<T>(self, other: T) -> Contains<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        Contains::new(self, other.as_expression())
    }

    /// Compares whether an array is contained by another array, using the `<@` operator.
    /// This is the opposite of `contains`
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     posts {
    /// #         id -> Integer,
    /// #         tags -> Array<VarChar>,
    /// #     }
    /// # }
    /// #
    /// # // FIXME: We shouldn't need to define a users table here
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # #[derive(Insertable)]
    /// # #[table_name="posts"]
    /// # struct NewPost<'a> { tags: Vec<&'a str> }
    /// #
    /// # fn main() {
    /// #     use self::posts::dsl::*;
    /// #     let conn = establish_connection();
    /// #     conn.execute("DROP TABLE IF EXISTS posts").unwrap();
    /// #     conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)").unwrap();
    /// #
    /// diesel::insert_into(posts)
    ///     .values(&vec![
    ///         NewPost { tags: vec!["cool", "awesome"] },
    ///     ])
    ///     .execute(&conn)
    ///     .unwrap();
    ///
    /// let query = posts.select(id).filter(tags.is_contained_by(vec!["cool", "awesome", "amazing"]));
    /// assert_eq!(Ok(vec![1]), query.load(&conn));
    ///
    /// let query = posts.select(id).filter(tags.is_contained_by(vec!["cool"]));
    /// assert_eq!(Ok(Vec::new()), query.load::<i32>(&conn));
    /// # }
    /// ```
    fn is_contained_by<T>(self, other: T) -> IsContainedBy<Self, T::Expression>
    where
        T: AsExpression<Self::SqlType>,
    {
        IsContainedBy::new(self, other.as_expression())
    }
}

impl<T, ST> ArrayExpressionMethods<ST> for T
where
    T: Expression<SqlType = Array<ST>>,
{
}

use expression::operators::{Asc, Desc};

/// PostgreSQL expression methods related to sorting.
///
/// This trait is only implemented for `Asc` and `Desc`. Although `.asc` is
/// implicit if no order is given, you will need to call `.asc()` explicitly in
/// order to call these methods.
pub trait SortExpressionMethods: Sized {
    /// Specify that nulls should come before other values in this ordering.
    /// Normally, nulls come last when sorting in ascending order and first
    /// when sorting in descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # table! {
    /// #     foos {
    /// #         id -> Integer,
    /// #         foo -> Nullable<Integer>,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     let connection = connection_no_data();
    /// #     connection.execute("DROP TABLE IF EXISTS foos").unwrap();
    /// connection.execute("CREATE TABLE foos (id SERIAL PRIMARY KEY, foo INTEGER)").unwrap();
    /// connection.execute("INSERT INTO foos (foo) VALUES (NULL), (1), (2)").unwrap();
    ///
    /// #     use self::foos::dsl::*;
    /// assert_eq!(Ok(vec![Some(1), Some(2), None]),
    ///            foos.select(foo).order(foo.asc()).load(&connection));
    /// assert_eq!(Ok(vec![None, Some(1), Some(2)]),
    ///            foos.select(foo).order(foo.asc().nulls_first()).load(&connection));
    /// #     connection.execute("DROP TABLE foos").unwrap();
    /// # }
    /// ```
    fn nulls_first(self) -> NullsFirst<Self> {
        NullsFirst::new(self)
    }

    /// Specify that nulls should come after other values in this ordering.
    /// Normally, nulls come last when sorting in ascending order and first
    /// when sorting in descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # #[macro_use] extern crate diesel_codegen;
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # table! {
    /// #     foos {
    /// #         id -> Integer,
    /// #         foo -> Nullable<Integer>,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     let connection = connection_no_data();
    /// #     connection.execute("DROP TABLE IF EXISTS foos").unwrap();
    /// connection.execute("CREATE TABLE foos (id SERIAL PRIMARY KEY, foo INTEGER)").unwrap();
    /// connection.execute("INSERT INTO foos (foo) VALUES (NULL), (1), (2)").unwrap();
    ///
    /// #     use self::foos::dsl::*;
    /// assert_eq!(Ok(vec![None, Some(2), Some(1)]),
    ///            foos.select(foo).order(foo.desc()).load(&connection));
    /// assert_eq!(Ok(vec![Some(2), Some(1), None]),
    ///            foos.select(foo).order(foo.desc().nulls_last()).load(&connection));
    /// #     connection.execute("DROP TABLE foos").unwrap();
    /// # }
    /// ```
    fn nulls_last(self) -> NullsLast<Self> {
        NullsLast::new(self)
    }
}

impl<T> SortExpressionMethods for Asc<T> {}

impl<T> SortExpressionMethods for Desc<T> {}

/// PostgreSQL expression methods related to text.
///
/// This trait is implemented for all types that implement `Expression` where
/// the `SqlType` is `Text`
pub trait PgTextExpressionMethods: Expression<SqlType = Text> + Sized {
    /// Returns a SQL `ILIKE` expression
    fn ilike<T: AsExpression<Text>>(self, other: T) -> ILike<Self, T::Expression> {
        ILike::new(self.as_expression(), other.as_expression())
    }

    /// Returns a SQL `NOT ILIKE` expression
    fn not_ilike<T: AsExpression<Text>>(self, other: T) -> NotILike<Self, T::Expression> {
        NotILike::new(self.as_expression(), other.as_expression())
    }
}

impl<T: Expression<SqlType = Text>> PgTextExpressionMethods for T {}
<|endoftext|>


<commit_before>//! Data-types for feedback templates.

use crate::juniper_ext::*;
use serde::{Deserialize, Serialize};
use table::TableSection;

/// A feedback template, consisting of a list of sections.
/// The template can be rendered to users before evaluation,
/// and gradually filled with data coming from the evaluation.
pub type Template = Vec<Section>;

/// A section in the feedback template.
#[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
pub enum Section {
    /// A section containing tabular data.
    Table(TableSection),
}

pub mod valence {
    use serde::{Deserialize, Serialize};

    /// Qualitative feeling associated to a feedback item.
    ///
    /// These enum variants are meant to be used only to control the appearance of feedback items.
    /// They might not all be applicable in every context,
    /// and their precise interpretation may depend on the context.
    /// However, they are all intentionally gathered together for simplicity.
    #[derive(Debug, Copy, Clone, Serialize, Deserialize, juniper::GraphQLEnum)]
    pub enum Valence {
        /// A successful result.
        /// E.g., a award is given full score.
        Success,
        /// A partial success.
        /// E.g., a award is given partial score.
        Partial,
        /// A failed result.
        /// E.g., time limit exceeded causes the loss of an award.
        Failure,
        /// The user should pay attention to something because it could result in a future failure.
        /// E.g., memory usage approaches the limit.
        Warning,
        /// An operation is completed successfully, as usually expected.
        /// E.g., a submitted source compiles correctly.
        Nominal,
        /// An operation is not performed, because a previous _success_ makes it unnecessary.
        /// E.g., an award is not evaluated because already achieved.
        Skipped,
        /// An operation is not performed, because irrelevant in the context.
        /// E.g., the compilation of a source program written in Python is note performed.
        Ignored,
        /// An operation is not performed, because a previous _failure_ makes it unnecessary.
        /// E.g., a large test case is not evaluated because a solution fails in a smaller one.
        Blocked,
    }
}

/// Tabular feedback.
pub mod table {
    use serde::{Deserialize, Serialize};

    use crate::juniper_ext::*;
    use crate::rusage::{MemoryUsage, TimeUsage};
    use crate::{award, content::Text, evaluation::record::Key};

    /// Feedback section containing tabular data.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct TableSection {
        /// Caption of this table. Roughly corresponding to `<caption>` HTML tag.
        pub caption: Text,
        /// Columns of this table.
        pub cols: Vec<Col>,
        /// Row groups of this table.
        pub row_groups: Vec<RowGroup>,
    }

    /// A table column. Roughly corresponding to `<col>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Col {
        /// Name of this column, shown in a column header.
        pub title: Text,
        /// Kind of data shown in this column.
        pub content: ColContent,
    }

    /// A table row group. Roughly corresponding to `<tbody>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowGroup {
        /// Name of this row group, shown in an header.
        pub title: Text,
        /// Rows in this group.
        pub rows: Vec<Row>,
    }

    /// A table row. Roughly corresponding to `<tr>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Row {
        /// Kind of data shown in this row.
        pub content: RowContent,
        /// Cells in this row.
        pub cells: Vec<Cell>,
    }

    /// A table cell. Roughly corresponding to either `<td>` or `<th>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Cell {
        /// Kind of data shown in this cell.
        /// Must be compatible with the kind of data of the corresponding row and column.
        pub content: CellContent,
    }

    /// Describes the kind of data shown in a row.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum RowContent {
        /// Regular data.
        Data,
        /// Summary data for the whole row group.
        /// E.g., the total score, maximum resource usage, etc.
        GroupSummary,
    }

    /// Describes the kind of data shown in a column.
    #[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum ColContent {
        RowTitle(RowTitleColContent),
        RowNumber(RowNumberColContent),
        Score(ScoreColContent),
        Message(MessageColContent),
        TimeUsage(TimeUsageColContent),
        MemoryUsage(MemoryUsageColContent),
    }

    /// Column of row titles.
    /// Cells must contain `CellContent::RowTitle`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct RowTitleColContent;

    /// Column of row numbers.
    /// Cells must contain `CellContent::RowNumber`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct RowNumberColContent;

    /// Column of scores.
    /// Cells must contain `CellContent::Score` or `CellContent::Missing`.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct ScoreColContent {
        /// Score range that applies to all column cells.
        pub range: award::ScoreRange,
    }

    /// Column of text messages.
    /// Cells must contain `CellContent::Message` or `CellContent::Missing`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct MessageColContent;

    /// Column containing amounts of time used for computation.
    /// Cells must contain `CellContent::TimeUsage`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct TimeUsageColContent;

    /// Column containing amounts of memory used for computation.
    /// Cells must contain `CellContent::MemoryUsage`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct MemoryUsageColContent;

    /// Describes the kind of data shown in a cell.
    #[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum CellContent {
        Missing(MissingCellContent),
        RowTitle(RowTitleCellContent),
        RowNumber(RowNumberCellContent),
        Score(ScoreCellContent),
        Message(MessageCellContent),
        TimeUsage(TimeUsageCellContent),
        MemoryUsage(MemoryUsageCellContent),
    }

    /// Cell containing no value.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct MissingCellContent;

    /// Cell containing the name of the corresponding row,
    /// shown as row header (e.g., using `<th scope=col>` elements).
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowTitleCellContent {
        pub title: Text,
    }

    /// Cell containing the number of the corresponding row,
    /// shown as row header (e.g., using `<th scope=col>` elements).
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowNumberCellContent {
        pub number: i32,
    }

    /// Cell containing a score.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct ScoreCellContent {
        /// Score range for this cell.
        /// Must be a sub-range of the column score range.
        pub range: award::ScoreRange,
        /// Reference to the evaluation value containing the score to show in this cell.
        pub key: Key,
    }

    /// Cell containing an amount of time used for computation.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct TimeUsageCellContent {
        /// Maximum time usage expected to be represented faithfully.
        /// Determines the scale of the representation (e.g., the units).
        pub max_relevant: TimeUsage,

        /// Time usage that should be presented as the main limit.
        pub primary_watermark: Option<TimeUsage>,

        // TODO: add secondary watermarks (each with a title)
        /// Time usage to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }

    /// Cell containing an amount of memory used for computation.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct MemoryUsageCellContent {
        /// Maximum memory usage expected to be represented faithfully.
        /// Determines the scale of the representation (e.g., the units).
        pub max_relevant: MemoryUsage,

        /// Memory usage that should be presented as the main limit.
        pub primary_watermark: Option<MemoryUsage>,

        // TODO: add secondary watermarks (each with a title)
        /// Memory usage to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }

    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct MessageCellContent {
        /// Message to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }
}
<commit_msg>Rename `CellContent::Missing` -> `NotAvailable`<commit_after>//! Data-types for feedback templates.

use crate::juniper_ext::*;
use serde::{Deserialize, Serialize};
use table::TableSection;

/// A feedback template, consisting of a list of sections.
/// The template can be rendered to users before evaluation,
/// and gradually filled with data coming from the evaluation.
pub type Template = Vec<Section>;

/// A section in the feedback template.
#[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
pub enum Section {
    /// A section containing tabular data.
    Table(TableSection),
}

pub mod valence {
    use serde::{Deserialize, Serialize};

    /// Qualitative feeling associated to a feedback item.
    ///
    /// These enum variants are meant to be used only to control the appearance of feedback items.
    /// They might not all be applicable in every context,
    /// and their precise interpretation may depend on the context.
    /// However, they are all intentionally gathered together for simplicity.
    #[derive(Debug, Copy, Clone, Serialize, Deserialize, juniper::GraphQLEnum)]
    pub enum Valence {
        /// A successful result.
        /// E.g., a award is given full score.
        Success,
        /// A partial success.
        /// E.g., a award is given partial score.
        Partial,
        /// A failed result.
        /// E.g., time limit exceeded causes the loss of an award.
        Failure,
        /// The user should pay attention to something because it could result in a future failure.
        /// E.g., memory usage approaches the limit.
        Warning,
        /// An operation is completed successfully, as usually expected.
        /// E.g., a submitted source compiles correctly.
        Nominal,
        /// An operation is not performed, because a previous _success_ makes it unnecessary.
        /// E.g., an award is not evaluated because already achieved.
        Skipped,
        /// An operation is not performed, because irrelevant in the context.
        /// E.g., the compilation of a source program written in Python is note performed.
        Ignored,
        /// An operation is not performed, because a previous _failure_ makes it unnecessary.
        /// E.g., a large test case is not evaluated because a solution fails in a smaller one.
        Blocked,
    }
}

/// Tabular feedback.
pub mod table {
    use serde::{Deserialize, Serialize};

    use crate::juniper_ext::*;
    use crate::rusage::{MemoryUsage, TimeUsage};
    use crate::{award, content::Text, evaluation::record::Key};

    /// Feedback section containing tabular data.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct TableSection {
        /// Caption of this table. Roughly corresponding to `<caption>` HTML tag.
        pub caption: Text,
        /// Columns of this table.
        pub cols: Vec<Col>,
        /// Row groups of this table.
        pub row_groups: Vec<RowGroup>,
    }

    /// A table column. Roughly corresponding to `<col>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Col {
        /// Name of this column, shown in a column header.
        pub title: Text,
        /// Kind of data shown in this column.
        pub content: ColContent,
    }

    /// A table row group. Roughly corresponding to `<tbody>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowGroup {
        /// Name of this row group, shown in an header.
        pub title: Text,
        /// Rows in this group.
        pub rows: Vec<Row>,
    }

    /// A table row. Roughly corresponding to `<tr>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Row {
        /// Kind of data shown in this row.
        pub content: RowContent,
        /// Cells in this row.
        pub cells: Vec<Cell>,
    }

    /// A table cell. Roughly corresponding to either `<td>` or `<th>` HTML element.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct Cell {
        /// Kind of data shown in this cell.
        /// Must be compatible with the kind of data of the corresponding row and column.
        pub content: CellContent,
    }

    /// Describes the kind of data shown in a row.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum RowContent {
        /// Regular data.
        Data,
        /// Summary data for the whole row group.
        /// E.g., the total score, maximum resource usage, etc.
        GroupSummary,
    }

    /// Describes the kind of data shown in a column.
    #[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum ColContent {
        RowTitle(RowTitleColContent),
        RowNumber(RowNumberColContent),
        Score(ScoreColContent),
        Message(MessageColContent),
        TimeUsage(TimeUsageColContent),
        MemoryUsage(MemoryUsageColContent),
    }

    /// Column of row titles.
    /// Cells must contain `CellContent::RowTitle`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct RowTitleColContent;

    /// Column of row numbers.
    /// Cells must contain `CellContent::RowNumber`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct RowNumberColContent;

    /// Column of scores.
    /// Cells must contain `CellContent::Score` or `CellContent::NotAvailable`.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct ScoreColContent {
        /// Score range that applies to all column cells.
        pub range: award::ScoreRange,
    }

    /// Column of text messages.
    /// Cells must contain `CellContent::Message` or `CellContent::NotAvailable`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct MessageColContent;

    /// Column containing amounts of time used for computation.
    /// Cells must contain `CellContent::TimeUsage`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct TimeUsageColContent;

    /// Column containing amounts of memory used for computation.
    /// Cells must contain `CellContent::MemoryUsage`.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct MemoryUsageColContent;

    /// Describes the kind of data shown in a cell.
    #[derive(Serialize, Deserialize, Clone, GraphQLUnionFromEnum)]
    #[serde(rename_all = "snake_case")]
    pub enum CellContent {
        NotAvailable(NotAvailableCellContent),
        RowTitle(RowTitleCellContent),
        RowNumber(RowNumberCellContent),
        Score(ScoreCellContent),
        Message(MessageCellContent),
        TimeUsage(TimeUsageCellContent),
        MemoryUsage(MemoryUsageCellContent),
    }

    /// Cell containing no value.
    #[derive(Serialize, Deserialize, Clone, GraphQLObjectFromUnit)]
    pub struct NotAvailableCellContent;

    /// Cell containing the name of the corresponding row,
    /// shown as row header (e.g., using `<th scope=col>` elements).
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowTitleCellContent {
        pub title: Text,
    }

    /// Cell containing the number of the corresponding row,
    /// shown as row header (e.g., using `<th scope=col>` elements).
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct RowNumberCellContent {
        pub number: i32,
    }

    /// Cell containing a score.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct ScoreCellContent {
        /// Score range for this cell.
        /// Must be a sub-range of the column score range.
        pub range: award::ScoreRange,
        /// Reference to the evaluation value containing the score to show in this cell.
        pub key: Key,
    }

    /// Cell containing an amount of time used for computation.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct TimeUsageCellContent {
        /// Maximum time usage expected to be represented faithfully.
        /// Determines the scale of the representation (e.g., the units).
        pub max_relevant: TimeUsage,

        /// Time usage that should be presented as the main limit.
        pub primary_watermark: Option<TimeUsage>,

        // TODO: add secondary watermarks (each with a title)
        /// Time usage to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }

    /// Cell containing an amount of memory used for computation.
    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct MemoryUsageCellContent {
        /// Maximum memory usage expected to be represented faithfully.
        /// Determines the scale of the representation (e.g., the units).
        pub max_relevant: MemoryUsage,

        /// Memory usage that should be presented as the main limit.
        pub primary_watermark: Option<MemoryUsage>,

        // TODO: add secondary watermarks (each with a title)
        /// Memory usage to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }

    #[derive(Serialize, Deserialize, Clone, juniper::GraphQLObject)]
    pub struct MessageCellContent {
        /// Message to show in this cell (reference).
        pub key: Key,
        /// Valence associated with this cell, if any (reference).
        pub valence_key: Option<Key>,
    }
}
<|endoftext|>


<commit_before>// use to create a .so/.dll
#![crate_type = "dylib"]

extern crate libc;

use std::mem::transmute;
use libc::types::common::c95::c_void;

// used to have this use function callable from C
// 1. no_mangle garanty the name will stay rust_print
// 2. pub extern garanty the name is exported
#[no_mangle]
pub extern fn vector_create() -> *mut c_void {

    let vector : Box<Vec<String>> = box vec![
        "你好".to_string(),
        "好".to_string()
    ];

    unsafe {transmute(vector)}
}

#[no_mangle]
pub extern fn vector_size(vector: &Vec<String>) -> u32 {

    vector.len() as u32
}

#[no_mangle]
pub extern fn vector_get(
    vector: &Vec<String> ,
    index: u32
) -> *const libc::c_char {

    // (*vector) should not be necessary, there's a bug in current
    // rust (as of end of september 2014) which force us to do that
    unsafe { (*vector)[index as uint].to_c_str().unwrap() }

}

#[no_mangle]
pub extern fn vector_print(
    vector: &Vec<String>
) {

    for value in vector.iter() {
        println!("from rust {}", value);
    }
}
<commit_msg>removed use of transmute, void pointer and libc in 'vector of string from rust' example<commit_after>// use to create a .so/.dll
#![crate_type = "dylib"]

/// create a new vector with some values inside for test
///
/// note: we can return directly a Box<Vec<>> and use it
/// as a pointer from C, because as Vec is not a dynamically sized
/// type, we're garantueed that Box is a single pointer
///
/// note2: after using vector_create from C, we will need to destroy
/// the value ourselves
#[no_mangle]
pub extern fn vector_create() -> Box<Vec<String>> {

    let vector : Box<Vec<String>> = box vec![
        "你好".to_string(),
        "好".to_string()
    ];

    vector
}

/// get the size of the vector given in parameter
///
///
#[no_mangle]
pub extern fn vector_size(vector: &Vec<String>) -> u32 {

    vector.len() as u32
}

/// permit to do vector[index] from C
///
/// note: to be 100% correct we should returned
/// *const libc::c_char, but that would required to use the
/// crate libc
///
/// note2: we need to free the pointer returned by this function
/// ourselves
#[no_mangle]
pub extern fn vector_get(
    vector: &Vec<String> ,
    index: u32
) -> *const i8 {

    // (*vector) should not be necessary, there's a bug in current
    // rust (as of end of september 2014) which force us to do that
    unsafe { (*vector)[index as uint].to_c_str().unwrap() }

}

/// simple debug function to print the content of a vector
///
///
#[no_mangle]
pub extern fn vector_print(
    vector: &Vec<String>
) {

    for value in vector.iter() {
        println!("from rust {}", value);
    }
}
<|endoftext|>


<commit_before>use crate::SlotProcessingError;
use hashing::hash;
use int_to_bytes::int_to_bytes32;
use log::{debug, trace};
use ssz::{ssz_encode, TreeHash};
use types::*;

const PHASE_0_CUSTODY_BIT: bool = false;

#[derive(Debug, PartialEq)]
pub enum Error {
    DBError(String),
    StateAlreadyTransitioned,
    PresentSlotIsNone,
    UnableToDecodeBlock,
    MissingParentState(Hash256),
    InvalidParentState(Hash256),
    MissingBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    MissingParentBlock(Hash256),
    StateSlotMismatch,
    BadBlockSignature,
    BadRandaoSignature,
    MaxProposerSlashingsExceeded,
    BadProposerSlashing,
    MaxAttestationsExceeded,
    InvalidAttestation(AttestationValidationError),
    NoBlockRoot,
    MaxDepositsExceeded,
    BadDeposit,
    MaxExitsExceeded,
    BadExit,
    BadCustodyReseeds,
    BadCustodyChallenges,
    BadCustodyResponses,
    BeaconStateError(BeaconStateError),
    SlotProcessingError(SlotProcessingError),
}

#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
    IncludedTooEarly,
    IncludedTooLate,
    WrongJustifiedSlot,
    WrongJustifiedRoot,
    BadLatestCrosslinkRoot,
    BadSignature,
    ShardBlockRootNotZero,
    NoBlockRoot,
    BeaconStateError(BeaconStateError),
}

macro_rules! ensure {
    ($condition: expr, $result: expr) => {
        if !$condition {
            return Err($result);
        }
    };
}

pub trait BlockProcessable {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error>;
    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error>;
}

impl BlockProcessable for BeaconState {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, true, spec)
    }

    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, false, spec)
    }
}

fn per_block_processing_signature_optional(
    state: &mut BeaconState,
    block: &BeaconBlock,
    verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    ensure!(block.slot == state.slot, Error::StateSlotMismatch);

    // Building the previous epoch could be delayed until an attestation from a previous epoch is
    // included. This is left for future optimisation.
    state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    /*
     * Proposer Signature
     */
    let block_proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
    let block_proposer = &state.validator_registry[block_proposer_index];

    if verify_block_signature {
        ensure!(
            bls_verify(
                &block_proposer.pubkey,
                &block.proposal_root(spec)[..],
                &block.signature,
                get_domain(&state.fork, state.current_epoch(spec), spec.domain_proposal)
            ),
            Error::BadBlockSignature
        );
    }

    /*
     * RANDAO
     */
    ensure!(
        bls_verify(
            &block_proposer.pubkey,
            &int_to_bytes32(state.current_epoch(spec).as_u64()),
            &block.randao_reveal,
            get_domain(&state.fork, state.current_epoch(spec), spec.domain_randao)
        ),
        Error::BadRandaoSignature
    );

    // TODO: check this is correct.
    let new_mix = {
        let mut mix = state.latest_randao_mixes
            [state.slot.as_usize() % spec.latest_randao_mixes_length]
            .to_vec();
        mix.append(&mut ssz_encode(&block.randao_reveal));
        Hash256::from(&hash(&mix)[..])
    };

    state.latest_randao_mixes[state.slot.as_usize() % spec.latest_randao_mixes_length] = new_mix;

    /*
     * Eth1 data
     */
    // TODO: Eth1 data processing.

    /*
     * Proposer slashings
     */
    ensure!(
        block.body.proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Error::MaxProposerSlashingsExceeded
    );
    for proposer_slashing in &block.body.proposer_slashings {
        let proposer = state
            .validator_registry
            .get(proposer_slashing.proposer_index as usize)
            .ok_or(Error::BadProposerSlashing)?;
        ensure!(
            proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.block_root
                != proposer_slashing.proposal_data_2.block_root,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer.penalized_epoch > state.current_epoch(spec),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_1.hash_tree_root(),
                &proposer_slashing.proposal_signature_1,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_1
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_2.hash_tree_root(),
                &proposer_slashing.proposal_signature_2,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_2
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        state.penalize_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    /*
     * Attestations
     */
    ensure!(
        block.body.attestations.len() as u64 <= spec.max_attestations,
        Error::MaxAttestationsExceeded
    );

    debug!("Verifying {} attestations.", block.body.attestations.len());

    for attestation in &block.body.attestations {
        validate_attestation(&state, attestation, spec)?;

        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
     */
    ensure!(
        block.body.deposits.len() as u64 <= spec.max_deposits,
        Error::MaxDepositsExceeded
    );

    // TODO: verify deposit merkle branches.
    for deposit in &block.body.deposits {
        debug!(
            "Processing deposit for pubkey {:?}",
            deposit.deposit_data.deposit_input.pubkey
        );
        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::BadDeposit)?;
    }

    /*
     * Exits
     */
    ensure!(
        block.body.exits.len() as u64 <= spec.max_exits,
        Error::MaxExitsExceeded
    );

    for exit in &block.body.exits {
        let validator = state
            .validator_registry
            .get(exit.validator_index as usize)
            .ok_or(Error::BadExit)?;
        ensure!(
            validator.exit_epoch
                > state.get_entry_exit_effect_epoch(state.current_epoch(spec), spec),
            Error::BadExit
        );
        ensure!(state.current_epoch(spec) >= exit.epoch, Error::BadExit);
        let exit_message = {
            let exit_struct = Exit {
                epoch: exit.epoch,
                validator_index: exit.validator_index,
                signature: spec.empty_signature.clone(),
            };
            exit_struct.hash_tree_root()
        };
        ensure!(
            bls_verify(
                &validator.pubkey,
                &exit_message,
                &exit.signature,
                get_domain(&state.fork, exit.epoch, spec.domain_exit)
            ),
            Error::BadProposerSlashing
        );
        state.initiate_validator_exit(exit.validator_index as usize);
    }

    debug!("State transition complete.");

    Ok(())
}

pub fn validate_attestation(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, true)
}

pub fn validate_attestation_without_signature(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, false)
}

fn validate_attestation_signature_optional(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
    verify_signature: bool,
) -> Result<(), AttestationValidationError> {
    trace!(
        "validate_attestation_signature_optional: attestation epoch: {}",
        attestation.data.slot.epoch(spec.epoch_length)
    );
    ensure!(
        attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot,
        AttestationValidationError::IncludedTooEarly
    );
    ensure!(
        attestation.data.slot + spec.epoch_length >= state.slot,
        AttestationValidationError::IncludedTooLate
    );
    if attestation.data.slot >= state.current_epoch_start_slot(spec) {
        ensure!(
            attestation.data.justified_epoch == state.justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    } else {
        ensure!(
            attestation.data.justified_epoch == state.previous_justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    }
    ensure!(
        attestation.data.justified_block_root
            == *state
                .get_block_root(
                    attestation
                        .data
                        .justified_epoch
                        .start_slot(spec.epoch_length),
                    &spec
                )
                .ok_or(AttestationValidationError::NoBlockRoot)?,
        AttestationValidationError::WrongJustifiedRoot
    );
    let potential_crosslink = Crosslink {
        shard_block_root: attestation.data.shard_block_root,
        epoch: attestation.data.slot.epoch(spec.epoch_length),
    };
    ensure!(
        (attestation.data.latest_crosslink
            == state.latest_crosslinks[attestation.data.shard as usize])
            | (attestation.data.latest_crosslink == potential_crosslink),
        AttestationValidationError::BadLatestCrosslinkRoot
    );
    if verify_signature {
        let participants = state.get_attestation_participants(
            &attestation.data,
            &attestation.aggregation_bitfield,
            spec,
        )?;
        trace!(
            "slot: {}, shard: {}, participants: {:?}",
            attestation.data.slot,
            attestation.data.shard,
            participants
        );
        let mut group_public_key = AggregatePublicKey::new();
        for participant in participants {
            group_public_key.add(
                state.validator_registry[participant as usize]
                    .pubkey
                    .as_raw(),
            )
        }
        ensure!(
            attestation.verify_signature(
                &group_public_key,
                PHASE_0_CUSTODY_BIT,
                get_domain(
                    &state.fork,
                    attestation.data.slot.epoch(spec.epoch_length),
                    spec.domain_attestation,
                )
            ),
            AttestationValidationError::BadSignature
        );
    }
    ensure!(
        attestation.data.shard_block_root == spec.zero_hash,
        AttestationValidationError::ShardBlockRootNotZero
    );
    Ok(())
}

fn get_domain(fork: &Fork, epoch: Epoch, domain_type: u64) -> u64 {
    fork.get_domain(epoch, domain_type)
}

fn bls_verify(pubkey: &PublicKey, message: &[u8], signature: &Signature, domain: u64) -> bool {
    signature.verify(message, domain, pubkey)
}

impl From<AttestationValidationError> for Error {
    fn from(e: AttestationValidationError) -> Error {
        Error::InvalidAttestation(e)
    }
}

impl From<BeaconStateError> for Error {
    fn from(e: BeaconStateError) -> Error {
        Error::BeaconStateError(e)
    }
}

impl From<SlotProcessingError> for Error {
    fn from(e: SlotProcessingError) -> Error {
        Error::SlotProcessingError(e)
    }
}

impl From<BeaconStateError> for AttestationValidationError {
    fn from(e: BeaconStateError) -> AttestationValidationError {
        AttestationValidationError::BeaconStateError(e)
    }
}
<commit_msg>Update per-block processing for new AggPub wrapper<commit_after>use crate::SlotProcessingError;
use hashing::hash;
use int_to_bytes::int_to_bytes32;
use log::{debug, trace};
use ssz::{ssz_encode, TreeHash};
use types::*;

const PHASE_0_CUSTODY_BIT: bool = false;

#[derive(Debug, PartialEq)]
pub enum Error {
    DBError(String),
    StateAlreadyTransitioned,
    PresentSlotIsNone,
    UnableToDecodeBlock,
    MissingParentState(Hash256),
    InvalidParentState(Hash256),
    MissingBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    MissingParentBlock(Hash256),
    StateSlotMismatch,
    BadBlockSignature,
    BadRandaoSignature,
    MaxProposerSlashingsExceeded,
    BadProposerSlashing,
    MaxAttestationsExceeded,
    InvalidAttestation(AttestationValidationError),
    NoBlockRoot,
    MaxDepositsExceeded,
    BadDeposit,
    MaxExitsExceeded,
    BadExit,
    BadCustodyReseeds,
    BadCustodyChallenges,
    BadCustodyResponses,
    BeaconStateError(BeaconStateError),
    SlotProcessingError(SlotProcessingError),
}

#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
    IncludedTooEarly,
    IncludedTooLate,
    WrongJustifiedSlot,
    WrongJustifiedRoot,
    BadLatestCrosslinkRoot,
    BadSignature,
    ShardBlockRootNotZero,
    NoBlockRoot,
    BeaconStateError(BeaconStateError),
}

macro_rules! ensure {
    ($condition: expr, $result: expr) => {
        if !$condition {
            return Err($result);
        }
    };
}

pub trait BlockProcessable {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error>;
    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error>;
}

impl BlockProcessable for BeaconState {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, true, spec)
    }

    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, false, spec)
    }
}

fn per_block_processing_signature_optional(
    state: &mut BeaconState,
    block: &BeaconBlock,
    verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    ensure!(block.slot == state.slot, Error::StateSlotMismatch);

    // Building the previous epoch could be delayed until an attestation from a previous epoch is
    // included. This is left for future optimisation.
    state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    /*
     * Proposer Signature
     */
    let block_proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
    let block_proposer = &state.validator_registry[block_proposer_index];

    if verify_block_signature {
        ensure!(
            bls_verify(
                &block_proposer.pubkey,
                &block.proposal_root(spec)[..],
                &block.signature,
                get_domain(&state.fork, state.current_epoch(spec), spec.domain_proposal)
            ),
            Error::BadBlockSignature
        );
    }

    /*
     * RANDAO
     */
    ensure!(
        bls_verify(
            &block_proposer.pubkey,
            &int_to_bytes32(state.current_epoch(spec).as_u64()),
            &block.randao_reveal,
            get_domain(&state.fork, state.current_epoch(spec), spec.domain_randao)
        ),
        Error::BadRandaoSignature
    );

    // TODO: check this is correct.
    let new_mix = {
        let mut mix = state.latest_randao_mixes
            [state.slot.as_usize() % spec.latest_randao_mixes_length]
            .to_vec();
        mix.append(&mut ssz_encode(&block.randao_reveal));
        Hash256::from(&hash(&mix)[..])
    };

    state.latest_randao_mixes[state.slot.as_usize() % spec.latest_randao_mixes_length] = new_mix;

    /*
     * Eth1 data
     */
    // TODO: Eth1 data processing.

    /*
     * Proposer slashings
     */
    ensure!(
        block.body.proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Error::MaxProposerSlashingsExceeded
    );
    for proposer_slashing in &block.body.proposer_slashings {
        let proposer = state
            .validator_registry
            .get(proposer_slashing.proposer_index as usize)
            .ok_or(Error::BadProposerSlashing)?;
        ensure!(
            proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.block_root
                != proposer_slashing.proposal_data_2.block_root,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer.penalized_epoch > state.current_epoch(spec),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_1.hash_tree_root(),
                &proposer_slashing.proposal_signature_1,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_1
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_2.hash_tree_root(),
                &proposer_slashing.proposal_signature_2,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_2
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        state.penalize_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    /*
     * Attestations
     */
    ensure!(
        block.body.attestations.len() as u64 <= spec.max_attestations,
        Error::MaxAttestationsExceeded
    );

    debug!("Verifying {} attestations.", block.body.attestations.len());

    for attestation in &block.body.attestations {
        validate_attestation(&state, attestation, spec)?;

        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
     */
    ensure!(
        block.body.deposits.len() as u64 <= spec.max_deposits,
        Error::MaxDepositsExceeded
    );

    // TODO: verify deposit merkle branches.
    for deposit in &block.body.deposits {
        debug!(
            "Processing deposit for pubkey {:?}",
            deposit.deposit_data.deposit_input.pubkey
        );
        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::BadDeposit)?;
    }

    /*
     * Exits
     */
    ensure!(
        block.body.exits.len() as u64 <= spec.max_exits,
        Error::MaxExitsExceeded
    );

    for exit in &block.body.exits {
        let validator = state
            .validator_registry
            .get(exit.validator_index as usize)
            .ok_or(Error::BadExit)?;
        ensure!(
            validator.exit_epoch
                > state.get_entry_exit_effect_epoch(state.current_epoch(spec), spec),
            Error::BadExit
        );
        ensure!(state.current_epoch(spec) >= exit.epoch, Error::BadExit);
        let exit_message = {
            let exit_struct = Exit {
                epoch: exit.epoch,
                validator_index: exit.validator_index,
                signature: spec.empty_signature.clone(),
            };
            exit_struct.hash_tree_root()
        };
        ensure!(
            bls_verify(
                &validator.pubkey,
                &exit_message,
                &exit.signature,
                get_domain(&state.fork, exit.epoch, spec.domain_exit)
            ),
            Error::BadProposerSlashing
        );
        state.initiate_validator_exit(exit.validator_index as usize);
    }

    debug!("State transition complete.");

    Ok(())
}

pub fn validate_attestation(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, true)
}

pub fn validate_attestation_without_signature(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, false)
}

fn validate_attestation_signature_optional(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
    verify_signature: bool,
) -> Result<(), AttestationValidationError> {
    trace!(
        "validate_attestation_signature_optional: attestation epoch: {}",
        attestation.data.slot.epoch(spec.epoch_length)
    );
    ensure!(
        attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot,
        AttestationValidationError::IncludedTooEarly
    );
    ensure!(
        attestation.data.slot + spec.epoch_length >= state.slot,
        AttestationValidationError::IncludedTooLate
    );
    if attestation.data.slot >= state.current_epoch_start_slot(spec) {
        ensure!(
            attestation.data.justified_epoch == state.justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    } else {
        ensure!(
            attestation.data.justified_epoch == state.previous_justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    }
    ensure!(
        attestation.data.justified_block_root
            == *state
                .get_block_root(
                    attestation
                        .data
                        .justified_epoch
                        .start_slot(spec.epoch_length),
                    &spec
                )
                .ok_or(AttestationValidationError::NoBlockRoot)?,
        AttestationValidationError::WrongJustifiedRoot
    );
    let potential_crosslink = Crosslink {
        shard_block_root: attestation.data.shard_block_root,
        epoch: attestation.data.slot.epoch(spec.epoch_length),
    };
    ensure!(
        (attestation.data.latest_crosslink
            == state.latest_crosslinks[attestation.data.shard as usize])
            | (attestation.data.latest_crosslink == potential_crosslink),
        AttestationValidationError::BadLatestCrosslinkRoot
    );
    if verify_signature {
        let participants = state.get_attestation_participants(
            &attestation.data,
            &attestation.aggregation_bitfield,
            spec,
        )?;
        trace!(
            "slot: {}, shard: {}, participants: {:?}",
            attestation.data.slot,
            attestation.data.shard,
            participants
        );
        let mut group_public_key = AggregatePublicKey::new();
        for participant in participants {
            group_public_key.add(&state.validator_registry[participant as usize].pubkey)
        }
        ensure!(
            attestation.verify_signature(
                &group_public_key,
                PHASE_0_CUSTODY_BIT,
                get_domain(
                    &state.fork,
                    attestation.data.slot.epoch(spec.epoch_length),
                    spec.domain_attestation,
                )
            ),
            AttestationValidationError::BadSignature
        );
    }
    ensure!(
        attestation.data.shard_block_root == spec.zero_hash,
        AttestationValidationError::ShardBlockRootNotZero
    );
    Ok(())
}

fn get_domain(fork: &Fork, epoch: Epoch, domain_type: u64) -> u64 {
    fork.get_domain(epoch, domain_type)
}

fn bls_verify(pubkey: &PublicKey, message: &[u8], signature: &Signature, domain: u64) -> bool {
    signature.verify(message, domain, pubkey)
}

impl From<AttestationValidationError> for Error {
    fn from(e: AttestationValidationError) -> Error {
        Error::InvalidAttestation(e)
    }
}

impl From<BeaconStateError> for Error {
    fn from(e: BeaconStateError) -> Error {
        Error::BeaconStateError(e)
    }
}

impl From<SlotProcessingError> for Error {
    fn from(e: SlotProcessingError) -> Error {
        Error::SlotProcessingError(e)
    }
}

impl From<BeaconStateError> for AttestationValidationError {
    fn from(e: BeaconStateError) -> AttestationValidationError {
        AttestationValidationError::BeaconStateError(e)
    }
}
<|endoftext|>


<commit_before>use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

use if_chain::if_chain;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    ///
    /// // More readable
    /// x += ", World";
    /// x.push_str(", World");
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let bs = "a byte string".as_bytes();
    ///
    /// // Good
    /// let bs = b"a byte string";
    /// ```
    pub STRING_LIT_AS_BYTES,
    nursery,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'tcx> LateLintPass<'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if in_external_macro(cx.sess(), e.span) {
            return;
        }

        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src, _) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
}

fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        use crate::utils::{snippet, snippet_with_applicability};
        use rustc_ast::LitKind;

        if_chain! {
            if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
            if path.ident.name == sym!(as_bytes);
            if let ExprKind::Lit(lit) = &args[0].kind;
            if let LitKind::Str(lit_content, _) = &lit.node;
            then {
                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                let mut applicability = Applicability::MachineApplicable;
                if callsite.starts_with("include_str!") {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on `include_str!(..)`",
                        "consider using `include_bytes!(..)` instead",
                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                            "include_str",
                            "include_bytes",
                            1,
                        ),
                        applicability,
                    );
                } else if lit_content.as_str().is_ascii()
                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                    && !args[0].span.from_expansion()
                {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on a string literal",
                        "consider using a byte string literal instead",
                        format!(
                            "b{}",
                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                        ),
                        applicability,
                    );
                }
            }
        }
    }
}
<commit_msg>Document string_lit_as_bytes known problems<commit_after>use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

use if_chain::if_chain;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    ///
    /// // More readable
    /// x += ", World";
    /// x.push_str(", World");
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:**
    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
    /// equivalent because they have different types. The former is `&[u8]`
    /// while the latter is `&[u8; 3]`. That means in general they will have a
    /// different set of methods and different trait implementations.
    ///
    /// ```rust
    /// fn f(v: Vec<u8>) {}
    ///
    /// f("...".as_bytes().to_owned()); // works
    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
    ///
    /// fn g(r: impl std::io::Read) {}
    ///
    /// g("...".as_bytes()); // works
    /// g(b"..."); // does not work
    /// ```
    ///
    /// The actual equivalent of `"str".as_bytes()` with the same type is not
    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
    /// more readable than a function call.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let bs = "a byte string".as_bytes();
    ///
    /// // Good
    /// let bs = b"a byte string";
    /// ```
    pub STRING_LIT_AS_BYTES,
    nursery,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'tcx> LateLintPass<'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if in_external_macro(cx.sess(), e.span) {
            return;
        }

        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src, _) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
}

fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        use crate::utils::{snippet, snippet_with_applicability};
        use rustc_ast::LitKind;

        if_chain! {
            if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
            if path.ident.name == sym!(as_bytes);
            if let ExprKind::Lit(lit) = &args[0].kind;
            if let LitKind::Str(lit_content, _) = &lit.node;
            then {
                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                let mut applicability = Applicability::MachineApplicable;
                if callsite.starts_with("include_str!") {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on `include_str!(..)`",
                        "consider using `include_bytes!(..)` instead",
                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                            "include_str",
                            "include_bytes",
                            1,
                        ),
                        applicability,
                    );
                } else if lit_content.as_str().is_ascii()
                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                    && !args[0].span.from_expansion()
                {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on a string literal",
                        "consider using a byte string literal instead",
                        format!(
                            "b{}",
                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                        ),
                        applicability,
                    );
                }
            }
        }
    }
}
<|endoftext|>