<commit_before>/*
 * How to get and parse the arguments on the command line
 */
extern mod std;
use std::getopts::*;

fn print_usage(program: ~str) {
   fail fmt!("Usage: %s -p port -s pool_size -d web_dir", program);
}

// My personal version of the parsing of arguments. We iterate over
// args to find the needed ones.
fn parse_arguments_with_iteration(args: ~[~str]) -> (int, int, ~str) {
   let mut port: int = -1;
   let mut pool_size: int = -1;
   let mut web_dir: ~str = ~"";
   let mut i = 1;

   while i<args.len() {
      match args[i] {
         ~"-p" =>  { port = int::from_str(args[i+1]).get();  i+=1}
         ~"-s" =>  { pool_size = int::from_str(args[i+1]).get();  i+=1}
         ~"-d" =>  { web_dir = copy args[i+1]; i+=1}
         _ => io::println(fmt!("Argument %s is unknown", args[i]))
      }
      i+=1;
   }

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

// Another version to parse the arguments, which uses getopts
fn parse_arguments_with_getopts(args: ~[~str]) -> (int, int, ~str) {
   let opts = ~[
      optopt("p"),
      optopt("s"),
      optopt("d")
   ];
   let matches = match getopts(vec::tail(args), opts) {
      result::Ok(m) => { m }
      result::Err(f) => { fail fail_str(f) }
   };
   let port = int::from_str(opt_str(&matches, "p")).get();
   let pool_size = int::from_str(opt_str(&matches, "s")).get();
   let web_dir = opt_str(&matches, "d");

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

fn main()  {
   let args : ~[~str] = os::args();
   if (args.len() != 7) {
      io::print("Bad length: ");
      print_usage(copy args[0]);
   }

   //let (port, pool_size, web_dir) = parse_arguments_with_iteration(args);
   let (port, pool_size, web_dir) = parse_arguments_with_getopts(args);

   //to play with string concatenation
   io::println(~"port is " + int::to_str(port, 10));
   io::println(~"pool size is " + int::to_str(pool_size, 10));
   io::println(~"web dir is " + web_dir);
}

<commit_msg>formatting<commit_after>/*
 * How to get and parse the arguments on the command line
 */
extern mod std;
use std::getopts::*;

fn print_usage(program: ~str) {
   fail fmt!("Usage: %s -p port -s pool_size -d web_dir", program);
}

// My personal version of the parsing of arguments. We iterate over
// args to find the needed ones.
fn parse_arguments_with_iteration(args: ~[~str]) -> (int, int, ~str) {
   let mut port: int = -1;
   let mut pool_size: int = -1;
   let mut web_dir: ~str = ~"";
   let mut i = 1;

   while i<args.len() {
      match args[i] {
         ~"-p" =>  { port = int::from_str(args[i+1]).get();  i+=1}
         ~"-s" =>  { pool_size = int::from_str(args[i+1]).get();  i+=1}
         ~"-d" =>  { web_dir = copy args[i+1]; i+=1}
         _ => io::println(fmt!("Argument %s is unknown", args[i]))
      }
      i+=1;
   }

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

// Another version to parse the arguments, which uses getopts
fn parse_arguments_with_getopts(args: ~[~str]) -> (int, int, ~str) {
   let opts = ~[
      optopt("p"),
      optopt("s"),
      optopt("d")
   ];
   let matches = match getopts(vec::tail(args), opts) {
      result::Ok(m) => { m }
      result::Err(f) => { fail fail_str(f) }
   };
   let port = int::from_str(opt_str(&matches, "p")).get();
   let pool_size = int::from_str(opt_str(&matches, "s")).get();
   let web_dir = opt_str(&matches, "d");

   if port == -1 || pool_size == -1 || web_dir == ~"" {
      io::println("Bad arguments values: ");
      print_usage(copy args[0]);
   }

   (port, pool_size, web_dir)
}

fn main()  {
   let args : ~[~str] = os::args();
   if (args.len() != 7) {
      io::print("Bad length: ");
      print_usage(copy args[0]);
   }

   //let (port, pool_size, web_dir) = parse_arguments_with_iteration(args);
   let (port, pool_size, web_dir) = parse_arguments_with_getopts(args);

   //to play with string concatenation
   io::println(~"port is " + int::to_str(port, 10));
   io::println(~"pool size is " + int::to_str(pool_size, 10));
   io::println(~"web dir is " + web_dir);
}

<|endoftext|>


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

use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};

/// BaseMetric is a struct used by `Counter` and `Gauge`
struct BaseMetric {
    counter_name: String,
    counter_help: String,
    counter: AtomicI64,
}

impl BaseMetric {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            counter_name,
            counter_help,
            counter: std::sync::atomic::AtomicI64::new(0),
        }
    }

    pub fn inc_by(&self, i: i64) {
        self.counter.fetch_add(i, Ordering::Relaxed);
    }

    pub fn inc(&self) {
        self.inc_by(1);
    }

    pub fn set(&self, i: i64) {
        self.counter.store(i, Ordering::Relaxed);
    }
}

/// PushMetricFormat contains a single function which converts the
/// metric into a string format which can be pushed to Prometheus
pub trait PushMetricFormat {
    fn get_push_metric_format(&self) -> String;
}

/// A Counter is a cumulative metric that represents a single
/// monotonically increasing counter whose value can only
/// increase or be reset to zero on restart.
pub struct Counter {
    base_counter: BaseMetric,
}

impl Counter {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            base_counter: BaseMetric::new(counter_name, counter_help),
        }
    }

    pub fn inc_by(&self, i: i64) {
        self.base_counter.inc_by(i);
    }

    pub fn inc(&self) {
        self.base_counter.inc();
    }
}

impl PushMetricFormat for Counter {
    fn get_push_metric_format(&self) -> String {
        format!(
            "# HELP {} {}\n# TYPE {} {}\n{} {}\n",
            self.base_counter.counter_name,
            self.base_counter.counter_help,
            self.base_counter.counter_name,
            "counter",
            self.base_counter.counter_name,
            self.base_counter.counter.load(Ordering::Relaxed)
        )
    }
}

/// A Gauge is a metric that represents a single
/// numerical value that can arbitrarily go up and down.
pub struct Gauge {
    base_counter: BaseMetric,
    has_been_set: AtomicBool,
}

impl Gauge {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            base_counter: BaseMetric::new(counter_name, counter_help),
            has_been_set: AtomicBool::new(false),
        }
    }

    pub fn set(&self, i: i64) {
        self.has_been_set.store(true, Ordering::Relaxed);
        self.base_counter.set(i);
    }
}

impl PushMetricFormat for Gauge {
    fn get_push_metric_format(&self) -> String {
        if self.has_been_set.load(Ordering::Relaxed) {
            format!(
                "# HELP {} {}\n# TYPE {} {}\n{} {}\n",
                self.base_counter.counter_name,
                self.base_counter.counter_help,
                self.base_counter.counter_name,
                "gauge",
                self.base_counter.counter_name,
                self.base_counter.counter.load(Ordering::Relaxed)
            )
        } else {
            String::new()
        }
    }
}

pub trait Metrics {
    fn get_metrics(&self) -> Vec<&dyn PushMetricFormat>;
}
<commit_msg>Removing set from secure/push-metrics/src/counters.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};

/// BaseMetric is a struct used by `Counter` and `Gauge`
struct BaseMetric {
    counter_name: String,
    counter_help: String,
    counter: AtomicI64,
}

impl BaseMetric {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            counter_name,
            counter_help,
            counter: std::sync::atomic::AtomicI64::new(0),
        }
    }

    pub fn inc_by(&self, i: i64) {
        self.counter.fetch_add(i, Ordering::Relaxed);
    }

    pub fn inc(&self) {
        self.inc_by(1);
    }
}

/// PushMetricFormat contains a single function which converts the
/// metric into a string format which can be pushed to Prometheus
pub trait PushMetricFormat {
    fn get_push_metric_format(&self) -> String;
}

/// A Counter is a cumulative metric that represents a single
/// monotonically increasing counter whose value can only
/// increase or be reset to zero on restart.
pub struct Counter {
    base_counter: BaseMetric,
}

impl Counter {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            base_counter: BaseMetric::new(counter_name, counter_help),
        }
    }

    pub fn inc_by(&self, i: i64) {
        self.base_counter.inc_by(i);
    }

    pub fn inc(&self) {
        self.base_counter.inc();
    }
}

impl PushMetricFormat for Counter {
    fn get_push_metric_format(&self) -> String {
        format!(
            "# HELP {} {}\n# TYPE {} {}\n{} {}\n",
            self.base_counter.counter_name,
            self.base_counter.counter_help,
            self.base_counter.counter_name,
            "counter",
            self.base_counter.counter_name,
            self.base_counter.counter.load(Ordering::Relaxed)
        )
    }
}

/// A Gauge is a metric that represents a single
/// numerical value that can arbitrarily go up and down.
pub struct Gauge {
    base_counter: BaseMetric,
    has_been_set: AtomicBool,
}

impl Gauge {
    pub fn new(counter_name: String, counter_help: String) -> Self {
        Self {
            base_counter: BaseMetric::new(counter_name, counter_help),
            has_been_set: AtomicBool::new(false),
        }
    }
}

impl PushMetricFormat for Gauge {
    fn get_push_metric_format(&self) -> String {
        if self.has_been_set.load(Ordering::Relaxed) {
            format!(
                "# HELP {} {}\n# TYPE {} {}\n{} {}\n",
                self.base_counter.counter_name,
                self.base_counter.counter_help,
                self.base_counter.counter_name,
                "gauge",
                self.base_counter.counter_name,
                self.base_counter.counter.load(Ordering::Relaxed)
            )
        } else {
            String::new()
        }
    }
}

pub trait Metrics {
    fn get_metrics(&self) -> Vec<&dyn PushMetricFormat>;
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
<<<<<<< HEAD
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
=======
        order: Option<Box<QueryFragment<DB> + Send + 'a>>,
        limit: Box<QueryFragment<DB> + Send + 'a>,
        offset: Box<QueryFragment<DB> + Send + 'a>,
        group_by: Box<QueryFragment<DB> + Send + 'a>,
>>>>>>> Run rustfmt
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}
<commit_msg>Add a test that will fail if Boxed queries are not Send<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
<<<<<<< HEAD
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
=======
        order: Option<Box<QueryFragment<DB> + Send + 'a>>,
        limit: Box<QueryFragment<DB> + Send + 'a>,
        offset: Box<QueryFragment<DB> + Send + 'a>,
        group_by: Box<QueryFragment<DB> + Send + 'a>,
>>>>>>> Run rustfmt
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    use crate::backend::Backend;

    table! {
        users {
            id -> Integer,
        }
    }

    fn assert_send<T>(_: T) where T: Send {}

    fn assert_boxed_query_send<B: Backend>() {
        assert_send(users::table.into_boxed::<B>());
        assert_send(users::table.filter(users::id.eq(10)).into_boxed::<B>());
    }

    #[test]
    fn boxed_is_send() {
        #[cfg(feature = "postgres")]
        assert_boxed_query_send::<crate::pg::Pg>();

        #[cfg(feature = "sqlite")]
        assert_boxed_query_send::<crate::sqlite::Sqlite>();

        #[cfg(feature = "mysql")]
        assert_boxed_query_send::<crate::mysql::Mysql>();
    }
}
<|endoftext|>


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

use crate::{
    smoke_test_environment::SmokeTestEnvironment,
    test_utils::{
        compare_balances, load_backend_storage, load_libra_root_storage,
        setup_swarm_and_client_proxy,
    },
};
use libra_config::config::NodeConfig;
use libra_global_constants::{
    CONSENSUS_KEY, OPERATOR_ACCOUNT, OPERATOR_KEY, VALIDATOR_NETWORK_KEY,
};
use libra_management::storage::to_x25519;
use libra_operational_tool::test_helper::OperationalTool;
use libra_secure_json_rpc::VMStatusView;
use libra_secure_storage::{CryptoStorage, KVStorage, Storage};
use libra_types::{
    account_address::AccountAddress,
    account_config::{testnet_dd_account_address, treasury_compliance_account_address},
    chain_id::ChainId,
    transaction::authenticator::AuthenticationKey,
};
use std::convert::{TryFrom, TryInto};

#[test]
fn test_consensus_key_rotation() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the consensus key
    let (txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the config has been updated correctly with the new consensus key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_consensus_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .consensus_public_key;
    assert_eq!(new_consensus_key, config_consensus_key);

    // Verify that the validator set info contains the new consensus key
    let info_consensus_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .consensus_public_key
        .clone();
    assert_eq!(new_consensus_key, info_consensus_key);

    // Rotate the consensus key in storage manually and perform another rotation using the op_tool.
    // Here, we expected the op_tool to see that the consensus key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let mut storage: Storage = (&backend).try_into().unwrap();
    let rotated_consensus_key = storage.rotate_key(CONSENSUS_KEY).unwrap();
    let (_txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    assert_eq!(rotated_consensus_key, new_consensus_key);
}

#[test]
fn test_operator_key_rotation() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = OperationalTool::new(
        format!("http://127.0.0.1:{}", node_config.rpc.address.port()),
        ChainId::test(),
    );

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    let (txn_ctx, _) = op_tool.rotate_operator_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Rotate the consensus key to verify the operator key has been updated
    let (txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the config has been updated correctly with the new consensus key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_consensus_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .consensus_public_key;
    assert_eq!(new_consensus_key, config_consensus_key);
}

#[test]
fn test_operator_key_rotation_recovery() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = OperationalTool::new(
        format!("http://127.0.0.1:{}", node_config.rpc.address.port()),
        ChainId::test(),
    );

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the operator key
    let (txn_ctx, new_operator_key) = op_tool.rotate_operator_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Verify that the operator key was updated on-chain
    let mut storage: Storage = (&backend).try_into().unwrap();
    let operator_account = storage
        .get::<AccountAddress>(OPERATOR_ACCOUNT)
        .unwrap()
        .value;
    let account_resource = op_tool.account_resource(operator_account).unwrap();
    let on_chain_operator_key = hex::decode(account_resource.authentication_key).unwrap();
    assert_eq!(
        AuthenticationKey::ed25519(&new_operator_key),
        AuthenticationKey::try_from(on_chain_operator_key).unwrap()
    );

    // Rotate the operator key in storage manually and perform another rotation using the op tool.
    // Here, we expected the op_tool to see that the operator key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let rotated_operator_key = storage.rotate_key(OPERATOR_KEY).unwrap();
    let (txn_ctx, new_operator_key) = op_tool.rotate_operator_key(&backend).unwrap();
    assert_eq!(rotated_operator_key, new_operator_key);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Verify that the operator key was updated on-chain
    let account_resource = op_tool.account_resource(operator_account).unwrap();
    let on_chain_operator_key = hex::decode(account_resource.authentication_key).unwrap();
    assert_eq!(
        AuthenticationKey::ed25519(&new_operator_key),
        AuthenticationKey::try_from(on_chain_operator_key).unwrap()
    );
}

#[test]
fn test_network_key_rotation() {
    let num_nodes = 5;
    let mut swarm = SmokeTestEnvironment::new(num_nodes);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the validator network key
    let (txn_ctx, new_network_key) = op_tool.rotate_validator_network_key(&backend).unwrap();
    wait_for_transaction_on_all_nodes(
        &swarm,
        num_nodes,
        txn_ctx.address,
        txn_ctx.sequence_number + 1,
    );

    // Verify that config has been loaded correctly with new key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_network_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, config_network_key);

    // Verify that the validator set info contains the new network key
    let info_network_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, info_network_key);

    // Restart validator
    // At this point, the `add_node` call ensures connectivity to all nodes
    swarm.validator_swarm.kill_node(0);
    swarm.validator_swarm.add_node(0).unwrap();
}

#[test]
fn test_network_key_rotation_recovery() {
    let num_nodes = 5;
    let mut swarm = SmokeTestEnvironment::new(num_nodes);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the network key in storage manually and perform a key rotation using the op_tool.
    // Here, we expected the op_tool to see that the network key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let mut storage: Storage = (&backend).try_into().unwrap();
    let rotated_network_key = storage.rotate_key(VALIDATOR_NETWORK_KEY).unwrap();
    let (txn_ctx, new_network_key) = op_tool.rotate_validator_network_key(&backend).unwrap();
    assert_eq!(new_network_key, to_x25519(rotated_network_key).unwrap());

    // Ensure all nodes have received the transaction
    wait_for_transaction_on_all_nodes(
        &swarm,
        num_nodes,
        txn_ctx.address,
        txn_ctx.sequence_number + 1,
    );

    // Verify that config has been loaded correctly with new key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_network_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, config_network_key);

    // Verify that the validator set info contains the new network key
    let info_network_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, info_network_key);

    // Restart validator
    // At this point, the `add_node` call ensures connectivity to all nodes
    swarm.validator_swarm.kill_node(0);
    swarm.validator_swarm.add_node(0).unwrap();
}

#[test]
fn test_e2e_reconfiguration() {
    let (swarm, mut client_proxy_1) = setup_swarm_and_client_proxy(3, 1);
    let mut client_proxy_0 = swarm.get_validator_client(0, None);

    // Mint some coins and verify the balances have been updated
    client_proxy_1.create_next_account(false).unwrap();
    client_proxy_0.set_accounts(client_proxy_1.copy_all_accounts());
    client_proxy_1
        .mint_coins(&["mintb", "0", "10", "Coin1"], true)
        .unwrap();
    client_proxy_1
        .wait_for_transaction(treasury_compliance_account_address(), 1)
        .unwrap();
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_1.get_balances(&["b", "0"]).unwrap(),
    ));

    // Wait for the mint transaction to be processed by node 0
    client_proxy_0
        .wait_for_transaction(testnet_dd_account_address(), 1)
        .unwrap();
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));

    // Connect the operator tool to the second node's JSON RPC API
    let op_tool = swarm.get_op_tool(1);

    // Load libra root's on disk storage
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();
    let libra_root = load_libra_root_storage(&node_config);

    // Remove node 0
    let peer_id = swarm.get_validator(0).unwrap().validator_peer_id().unwrap();
    let context = op_tool.remove_validator(peer_id, &libra_root).unwrap();
    client_proxy_1
        .wait_for_transaction(context.address, context.sequence_number + 1)
        .unwrap();

    // Mint another 10 coins after removing node 0
    client_proxy_1
        .mint_coins(&["mintb", "0", "10", "Coin1"], true)
        .unwrap();
    assert!(compare_balances(
        vec![(20.0, "Coin1".to_string())],
        client_proxy_1.get_balances(&["b", "0"]).unwrap(),
    ));
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));

    // Add the node back
    let context = op_tool.add_validator(peer_id, &libra_root).unwrap();
    client_proxy_0
        .wait_for_transaction(context.address, context.sequence_number)
        .unwrap();

    // Wait for the node to catch up
    client_proxy_0
        .wait_for_transaction(testnet_dd_account_address(), 2)
        .unwrap();
    assert!(compare_balances(
        vec![(20.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));
}

fn wait_for_transaction_on_all_nodes(
    swarm: &SmokeTestEnvironment,
    num_nodes: usize,
    account: AccountAddress,
    sequence_number: u64,
) {
    for i in 0..num_nodes {
        let mut client = swarm.get_validator_client(i, None);
        client
            .wait_for_transaction(account, sequence_number)
            .unwrap();
    }
}
<commit_msg>[Smoke Test] Re-order smoke tests in operational tooling to be alphabetical.<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    smoke_test_environment::SmokeTestEnvironment,
    test_utils::{
        compare_balances, load_backend_storage, load_libra_root_storage,
        setup_swarm_and_client_proxy,
    },
};
use libra_config::config::NodeConfig;
use libra_global_constants::{
    CONSENSUS_KEY, OPERATOR_ACCOUNT, OPERATOR_KEY, VALIDATOR_NETWORK_KEY,
};
use libra_management::storage::to_x25519;
use libra_operational_tool::test_helper::OperationalTool;
use libra_secure_json_rpc::VMStatusView;
use libra_secure_storage::{CryptoStorage, KVStorage, Storage};
use libra_types::{
    account_address::AccountAddress,
    account_config::{testnet_dd_account_address, treasury_compliance_account_address},
    chain_id::ChainId,
    transaction::authenticator::AuthenticationKey,
};
use std::convert::{TryFrom, TryInto};

#[test]
fn test_consensus_key_rotation() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the consensus key
    let (txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the config has been updated correctly with the new consensus key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_consensus_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .consensus_public_key;
    assert_eq!(new_consensus_key, config_consensus_key);

    // Verify that the validator set info contains the new consensus key
    let info_consensus_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .consensus_public_key
        .clone();
    assert_eq!(new_consensus_key, info_consensus_key);

    // Rotate the consensus key in storage manually and perform another rotation using the op_tool.
    // Here, we expected the op_tool to see that the consensus key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let mut storage: Storage = (&backend).try_into().unwrap();
    let rotated_consensus_key = storage.rotate_key(CONSENSUS_KEY).unwrap();
    let (_txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    assert_eq!(rotated_consensus_key, new_consensus_key);
}

#[test]
fn test_e2e_reconfiguration() {
    let (swarm, mut client_proxy_1) = setup_swarm_and_client_proxy(3, 1);
    let mut client_proxy_0 = swarm.get_validator_client(0, None);

    // Mint some coins and verify the balances have been updated
    client_proxy_1.create_next_account(false).unwrap();
    client_proxy_0.set_accounts(client_proxy_1.copy_all_accounts());
    client_proxy_1
        .mint_coins(&["mintb", "0", "10", "Coin1"], true)
        .unwrap();
    client_proxy_1
        .wait_for_transaction(treasury_compliance_account_address(), 1)
        .unwrap();
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_1.get_balances(&["b", "0"]).unwrap(),
    ));

    // Wait for the mint transaction to be processed by node 0
    client_proxy_0
        .wait_for_transaction(testnet_dd_account_address(), 1)
        .unwrap();
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));

    // Connect the operator tool to the second node's JSON RPC API
    let op_tool = swarm.get_op_tool(1);

    // Load libra root's on disk storage
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();
    let libra_root = load_libra_root_storage(&node_config);

    // Remove node 0
    let peer_id = swarm.get_validator(0).unwrap().validator_peer_id().unwrap();
    let context = op_tool.remove_validator(peer_id, &libra_root).unwrap();
    client_proxy_1
        .wait_for_transaction(context.address, context.sequence_number + 1)
        .unwrap();

    // Mint another 10 coins after removing node 0
    client_proxy_1
        .mint_coins(&["mintb", "0", "10", "Coin1"], true)
        .unwrap();
    assert!(compare_balances(
        vec![(20.0, "Coin1".to_string())],
        client_proxy_1.get_balances(&["b", "0"]).unwrap(),
    ));
    assert!(compare_balances(
        vec![(10.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));

    // Add the node back
    let context = op_tool.add_validator(peer_id, &libra_root).unwrap();
    client_proxy_0
        .wait_for_transaction(context.address, context.sequence_number)
        .unwrap();

    // Wait for the node to catch up
    client_proxy_0
        .wait_for_transaction(testnet_dd_account_address(), 2)
        .unwrap();
    assert!(compare_balances(
        vec![(20.0, "Coin1".to_string())],
        client_proxy_0.get_balances(&["b", "0"]).unwrap(),
    ));
}

#[test]
fn test_network_key_rotation() {
    let num_nodes = 5;
    let mut swarm = SmokeTestEnvironment::new(num_nodes);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the validator network key
    let (txn_ctx, new_network_key) = op_tool.rotate_validator_network_key(&backend).unwrap();
    wait_for_transaction_on_all_nodes(
        &swarm,
        num_nodes,
        txn_ctx.address,
        txn_ctx.sequence_number + 1,
    );

    // Verify that config has been loaded correctly with new key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_network_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, config_network_key);

    // Verify that the validator set info contains the new network key
    let info_network_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, info_network_key);

    // Restart validator
    // At this point, the `add_node` call ensures connectivity to all nodes
    swarm.validator_swarm.kill_node(0);
    swarm.validator_swarm.add_node(0).unwrap();
}

#[test]
fn test_network_key_rotation_recovery() {
    let num_nodes = 5;
    let mut swarm = SmokeTestEnvironment::new(num_nodes);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = swarm.get_op_tool(0);

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the network key in storage manually and perform a key rotation using the op_tool.
    // Here, we expected the op_tool to see that the network key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let mut storage: Storage = (&backend).try_into().unwrap();
    let rotated_network_key = storage.rotate_key(VALIDATOR_NETWORK_KEY).unwrap();
    let (txn_ctx, new_network_key) = op_tool.rotate_validator_network_key(&backend).unwrap();
    assert_eq!(new_network_key, to_x25519(rotated_network_key).unwrap());

    // Ensure all nodes have received the transaction
    wait_for_transaction_on_all_nodes(
        &swarm,
        num_nodes,
        txn_ctx.address,
        txn_ctx.sequence_number + 1,
    );

    // Verify that config has been loaded correctly with new key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_network_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, config_network_key);

    // Verify that the validator set info contains the new network key
    let info_network_key = op_tool.validator_set(validator_account, &backend).unwrap()[0]
        .validator_network_address
        .find_noise_proto()
        .unwrap();
    assert_eq!(new_network_key, info_network_key);

    // Restart validator
    // At this point, the `add_node` call ensures connectivity to all nodes
    swarm.validator_swarm.kill_node(0);
    swarm.validator_swarm.add_node(0).unwrap();
}

#[test]
fn test_operator_key_rotation() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = OperationalTool::new(
        format!("http://127.0.0.1:{}", node_config.rpc.address.port()),
        ChainId::test(),
    );

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    let (txn_ctx, _) = op_tool.rotate_operator_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Rotate the consensus key to verify the operator key has been updated
    let (txn_ctx, new_consensus_key) = op_tool.rotate_consensus_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the config has been updated correctly with the new consensus key
    let validator_account = node_config.validator_network.as_ref().unwrap().peer_id();
    let config_consensus_key = op_tool
        .validator_config(validator_account, &backend)
        .unwrap()
        .consensus_public_key;
    assert_eq!(new_consensus_key, config_consensus_key);
}

#[test]
fn test_operator_key_rotation_recovery() {
    let mut swarm = SmokeTestEnvironment::new(5);
    swarm.validator_swarm.launch();

    // Load a node config
    let node_config =
        NodeConfig::load(swarm.validator_swarm.config.config_files.first().unwrap()).unwrap();

    // Connect the operator tool to the first node's JSON RPC API
    let op_tool = OperationalTool::new(
        format!("http://127.0.0.1:{}", node_config.rpc.address.port()),
        ChainId::test(),
    );

    // Load validator's on disk storage
    let backend = load_backend_storage(&&node_config);

    // Rotate the operator key
    let (txn_ctx, new_operator_key) = op_tool.rotate_operator_key(&backend).unwrap();
    let mut client = swarm.get_validator_client(0, None);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Verify that the operator key was updated on-chain
    let mut storage: Storage = (&backend).try_into().unwrap();
    let operator_account = storage
        .get::<AccountAddress>(OPERATOR_ACCOUNT)
        .unwrap()
        .value;
    let account_resource = op_tool.account_resource(operator_account).unwrap();
    let on_chain_operator_key = hex::decode(account_resource.authentication_key).unwrap();
    assert_eq!(
        AuthenticationKey::ed25519(&new_operator_key),
        AuthenticationKey::try_from(on_chain_operator_key).unwrap()
    );

    // Rotate the operator key in storage manually and perform another rotation using the op tool.
    // Here, we expected the op_tool to see that the operator key in storage doesn't match the one
    // on-chain, and thus it should simply forward a transaction to the blockchain.
    let rotated_operator_key = storage.rotate_key(OPERATOR_KEY).unwrap();
    let (txn_ctx, new_operator_key) = op_tool.rotate_operator_key(&backend).unwrap();
    assert_eq!(rotated_operator_key, new_operator_key);
    client
        .wait_for_transaction(txn_ctx.address, txn_ctx.sequence_number + 1)
        .unwrap();

    // Verify that the transaction was executed correctly
    let result = op_tool
        .validate_transaction(txn_ctx.address, txn_ctx.sequence_number)
        .unwrap();
    let vm_status = result.unwrap();
    assert_eq!(VMStatusView::Executed, vm_status);

    // Verify that the operator key was updated on-chain
    let account_resource = op_tool.account_resource(operator_account).unwrap();
    let on_chain_operator_key = hex::decode(account_resource.authentication_key).unwrap();
    assert_eq!(
        AuthenticationKey::ed25519(&new_operator_key),
        AuthenticationKey::try_from(on_chain_operator_key).unwrap()
    );
}

fn wait_for_transaction_on_all_nodes(
    swarm: &SmokeTestEnvironment,
    num_nodes: usize,
    account: AccountAddress,
    sequence_number: u64,
) {
    for i in 0..num_nodes {
        let mut client = swarm.get_validator_client(i, None);
        client
            .wait_for_transaction(account, sequence_number)
            .unwrap();
    }
}
<|endoftext|>


<commit_before>// ignore-windows: No libc on Windows
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

extern crate libc;

use std::env::temp_dir;
use std::fs::{File, remove_file};
use std::io::Write;
use std::os::unix::io::AsRawFd;

fn main() {
    let path = temp_dir().join("miri_test_libc.txt");
    // Cleanup before test
    remove_file(&path).ok();

    // Set up an open file
    let mut file = File::create(&path).unwrap();
    let bytes = b"Hello, World!\n";
    file.write(bytes).unwrap();

    // Test calling posix_fadvise on a file.
    let result = unsafe {
        libc::posix_fadvise(
            file.as_raw_fd(),
            0,
            bytes.len() as i64,
            libc::POSIX_FADV_DONTNEED,
        )
    };
    drop(file);
    remove_file(&path).unwrap();
    assert_eq!(result, 0);
}
<commit_msg>Try fixing test on i686-unknown-linux-gnu<commit_after>// ignore-windows: No libc on Windows
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]

extern crate libc;

use std::convert::TryInto;
use std::env::temp_dir;
use std::fs::{File, remove_file};
use std::io::Write;
use std::os::unix::io::AsRawFd;

fn main() {
    let path = temp_dir().join("miri_test_libc.txt");
    // Cleanup before test
    remove_file(&path).ok();

    // Set up an open file
    let mut file = File::create(&path).unwrap();
    let bytes = b"Hello, World!\n";
    file.write(bytes).unwrap();

    // Test calling posix_fadvise on a file.
    let result = unsafe {
        libc::posix_fadvise(
            file.as_raw_fd(),
            0,
            bytes.len().try_into().unwrap(),
            libc::POSIX_FADV_DONTNEED,
        )
    };
    drop(file);
    remove_file(&path).unwrap();
    assert_eq!(result, 0);
}
<|endoftext|>


<commit_before>use core::ptr;

use super::SDTHeader;

#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct SSDT {
    pub header: SDTHeader,
    pub data: &'static [u8]

}

impl SSDT {
    pub fn new(header: *const SDTHeader) -> Option<Self> {
        if unsafe { (*header).valid("SSDT") } {
            Some(SSDT {
                header: unsafe { *header },
                data: unsafe { (*header).data() }
            })
        } else {
            None
        }
    }
}
<commit_msg>Simplify `SSDT::new()` with fewer `unsafe` blocks<commit_after>use core::ptr;

use super::SDTHeader;

#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct SSDT {
    pub header: SDTHeader,
    pub data: &'static [u8]

}

impl SSDT {
    pub fn new(header: *const SDTHeader) -> Option<Self> {
        let header = unsafe { *header };
        if header.valid("SSDT") {
            Some(SSDT {
                header: header,
                data: header.data(),
            })
        } else {
            None
        }
    }
}
<|endoftext|>


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

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner, nsIDocument, self};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe {
            MediaListKey::from_raw(mem::transmute(self.0))
        }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::ServoMediaList;
        use std::mem;

        unsafe {
            let servo_media_list =
                self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
            if servo_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*servo_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode = unsafe {
            (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
        };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist.flush(
            &StylesheetGuards::same(guard),
            document_element,
        )
    }

    /// Returns whether private browsing is enabled.
    pub fn is_private_browsing_enabled(&self) -> bool {
        let doc =
            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { structs::StylePrefs_sVisitedLinksEnabled }
    }
    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        self.visited_links_enabled() && !self.is_private_browsing_enabled()
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<commit_msg>Auto merge of #19398 - emilio:visited-as-an-image, r=dholbert<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/. */

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner, nsIDocument, self};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe {
            MediaListKey::from_raw(mem::transmute(self.0))
        }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::ServoMediaList;
        use std::mem;

        unsafe {
            let servo_media_list =
                self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
            if servo_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*servo_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode = unsafe {
            (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
        };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist.flush(
            &StylesheetGuards::same(guard),
            document_element,
        )
    }

    /// Returns whether private browsing is enabled.
    fn is_private_browsing_enabled(&self) -> bool {
        let doc =
            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Returns whether the document is being used as an image.
    fn is_being_used_as_an_image(&self) -> bool {
        let doc =
            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();

        unsafe { (*doc).mIsBeingUsedAsImage() }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { structs::StylePrefs_sVisitedLinksEnabled }
    }

    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        if !self.visited_links_enabled() {
            return false;
        }

        if self.is_private_browsing_enabled() {
            return false;
        }

        if self.is_being_used_as_an_image() {
            return false;
        }

        true
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<|endoftext|>