<commit_before>use std::collections::HashSet;
use super::attestation_record::AttestationRecord;
use super::AttesterMap;
use super::attestation_parent_hashes::{
    attestation_parent_hashes,
    ParentHashesError,
};
use super::db::{
    ClientDB,
    DBError
};
use super::db::stores::{
    BlockStore,
    ValidatorStore,
};
use super::ssz::SszStream;
use super::utils::hash::canonical_hash;
use super::utils::types::{
    Hash256,
};
use std::sync::Arc;
use super::signatures::{
    verify_aggregate_signature_for_indices,
    SignatureVerificationError,
};

#[derive(Debug,PartialEq)]
pub enum AttestationValidationError {
    SlotTooHigh,
    SlotTooLow,
    JustifiedSlotTooHigh,
    UnknownJustifiedBlock,
    TooManyObliqueHashes,
    BadCurrentHashes,
    BadObliqueHashes,
    BadAttesterMap,
    IntWrapping,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    IncorrectBitField,
    NoSignatures,
    NonZeroTrailingBits,
    AggregateSignatureFail,
    DBError(String),
}

fn bytes_for_bits(bits: usize) -> usize {
    (bits.saturating_sub(1) / 8) + 1
}

fn any_of_last_n_bits_are_set(byte: &u8, n: usize) -> bool {
    let shift = 8_u8.saturating_sub(n as u8);
    ((!0 >> shift) & byte) > 0
}

pub fn validate_attestation<T>(a: &AttestationRecord,
                               block_slot: u64,
                               cycle_length: u8,
                               known_last_justified_slot: u64,
                               known_parent_hashes: Arc<Vec<Hash256>>,
                               block_store: Arc<BlockStore<T>>,
                               validator_store: Arc<ValidatorStore<T>>,
                               attester_map: Arc<AttesterMap>)
    -> Result<Option<HashSet<usize>>, AttestationValidationError>
    where T: ClientDB + Sized
{
    // TODO: assert attestion isn't already known

    /*
     * The attesation slot must not be higher than the block that contained it.
     */
    if a.slot > block_slot {
        return Err(AttestationValidationError::SlotTooHigh);
    }

    /*
     * The slot of this attestation must not be more than cycle_length + 1 distance
     * from the block that contained it.
     *
     * The below code stays overflow-safe as long as cycle length is a < 64 bit integer.
     */
    if a.slot < block_slot.saturating_sub(u64::from(cycle_length) + 1) {
        return Err(AttestationValidationError::SlotTooLow);
    }

    /*
     * The attestation must indicate that its last justified slot is the same as the last justified
     * slot known to us.
     */
    if a.justified_slot > known_last_justified_slot {
        return Err(AttestationValidationError::JustifiedSlotTooHigh);
    }

    /*
     * There is no need to include more oblique parents hashes than there are blocks
     * in a cycle.
     */
    if a.oblique_parent_hashes.len() > usize::from(cycle_length) {
        return Err(AttestationValidationError::TooManyObliqueHashes);
    }

    /*
     * Retrieve the set of attestation indices for this slot and shard id.
     *
     * This is an array mapping the order that validators will appear in the bitfield to the
     * canonincal index of a validator.
     */
    let attestation_indices = attester_map.get(&(a.slot, a.shard_id.into()))
        .ok_or(AttestationValidationError::BadAttesterMap)?;

    /*
     * The bitfield must be no longer than the minimum required to represent each validator in the
     * attestation indicies for this slot and shard id.
     */
    if a.attester_bitfield.num_bytes() !=
        bytes_for_bits(attestation_indices.len())
    {
        return Err(AttestationValidationError::IncorrectBitField);
    }

    /*
     * If there are excess bits in the bitfield because the number of a validators in not a
     * multiple of 8, reject this attestation record.
     *
     * Allow extra set bits would permit mutliple different byte layouts (and therefore hashes) to
     * refer to the same AttesationRecord.
     */
    let last_byte =
        a.attester_bitfield.get_byte(a.attester_bitfield.num_bytes())
        .ok_or(AttestationValidationError::IncorrectBitField)?;
    if any_of_last_n_bits_are_set(last_byte, a.attester_bitfield.len() % 8) {
        return Err(AttestationValidationError::IncorrectBitField)
    }

    /*
     * The specified justified block hash must be known to us
     */
    if !block_store.block_exists(&a.justified_block_hash)? {
        return Err(AttestationValidationError::UnknownJustifiedBlock)
    }

    let signed_message = {
        let parent_hashes = attestation_parent_hashes(
            cycle_length,
            block_slot,
            a.slot,
            &known_parent_hashes,
            &a.oblique_parent_hashes)?;
        generate_signed_message(
            a.slot,
            &parent_hashes,
            a.shard_id,
            &a.shard_block_hash,
            a.justified_slot)
    };

    let voted_hashmap =
        verify_aggregate_signature_for_indices(
            &signed_message,
            &a.aggregate_sig,
            &attestation_indices,
            &a.attester_bitfield,
            &validator_store)?;

    Ok(voted_hashmap)
}

/// Generates the message used to validate the signature provided with an AttestationRecord.
///
/// Ensures that the signer of the message has a view of the chain that is compatible with ours.
fn generate_signed_message(slot: u64,
                           parent_hashes: &[Hash256],
                           shard_id: u16,
                           shard_block_hash: &Hash256,
                           justified_slot: u64)
    -> Vec<u8>
{
    /*
     * Note: it's a little risky here to use SSZ, because the encoding is not necessarily SSZ
     * (for example, SSZ might change whilst this doesn't).
     *
     * I have suggested switching this to ssz here:
     * https://github.com/ethereum/eth2.0-specs/issues/5
     *
     * If this doesn't happen, it would be safer to not use SSZ at all.
     */
    let mut ssz_stream = SszStream::new();
    ssz_stream.append(&slot);
    for h in parent_hashes {
        ssz_stream.append_encoded_raw(&h.to_vec())
    }
    ssz_stream.append(&shard_id);
    ssz_stream.append(shard_block_hash);
    ssz_stream.append(&justified_slot);
    let bytes = ssz_stream.drain();
    canonical_hash(&bytes)
}

impl From<ParentHashesError> for AttestationValidationError {
    fn from(e: ParentHashesError) -> Self {
        match e {
            ParentHashesError::BadCurrentHashes
                => AttestationValidationError::BadCurrentHashes,
            ParentHashesError::BadObliqueHashes
                => AttestationValidationError::BadObliqueHashes,
            ParentHashesError::SlotTooLow
                => AttestationValidationError::SlotTooLow,
            ParentHashesError::SlotTooHigh
                => AttestationValidationError::SlotTooHigh,
            ParentHashesError::IntWrapping
                => AttestationValidationError::IntWrapping
        }
    }
}

impl From<DBError> for AttestationValidationError {
    fn from(e: DBError) -> Self {
        AttestationValidationError::DBError(e.message)
    }
}

impl From<SignatureVerificationError> for AttestationValidationError {
    fn from(e: SignatureVerificationError) -> Self {
        match e {
            SignatureVerificationError::BadValidatorIndex
                => AttestationValidationError::BadAttesterMap,
            SignatureVerificationError::PublicKeyCorrupt
                => AttestationValidationError::PublicKeyCorrupt,
            SignatureVerificationError::NoPublicKeyForValidator
                => AttestationValidationError::NoPublicKeyForValidator,
            SignatureVerificationError::DBError(s)
                => AttestationValidationError::DBError(s),
        }
    }
}
<commit_msg>Fix bit shift function in attestation validation<commit_after>use std::collections::HashSet;
use super::attestation_record::AttestationRecord;
use super::AttesterMap;
use super::attestation_parent_hashes::{
    attestation_parent_hashes,
    ParentHashesError,
};
use super::db::{
    ClientDB,
    DBError
};
use super::db::stores::{
    BlockStore,
    ValidatorStore,
};
use super::ssz::SszStream;
use super::utils::hash::canonical_hash;
use super::utils::types::{
    Hash256,
};
use std::sync::Arc;
use super::signatures::{
    verify_aggregate_signature_for_indices,
    SignatureVerificationError,
};

#[derive(Debug,PartialEq)]
pub enum AttestationValidationError {
    SlotTooHigh,
    SlotTooLow,
    JustifiedSlotTooHigh,
    UnknownJustifiedBlock,
    TooManyObliqueHashes,
    BadCurrentHashes,
    BadObliqueHashes,
    BadAttesterMap,
    IntWrapping,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    IncorrectBitField,
    NoSignatures,
    NonZeroTrailingBits,
    AggregateSignatureFail,
    DBError(String),
}

fn bytes_for_bits(bits: usize) -> usize {
    (bits.saturating_sub(1) / 8) + 1
}

fn any_of_last_n_bits_are_set(byte: &u8, n: usize) -> bool {
    let shift = 8_u16.saturating_sub(n as u16);
    ((!0 << shift) & u16::from(*byte)) > 0
}

pub fn validate_attestation<T>(a: &AttestationRecord,
                               block_slot: u64,
                               cycle_length: u8,
                               known_last_justified_slot: u64,
                               known_parent_hashes: Arc<Vec<Hash256>>,
                               block_store: Arc<BlockStore<T>>,
                               validator_store: Arc<ValidatorStore<T>>,
                               attester_map: Arc<AttesterMap>)
    -> Result<Option<HashSet<usize>>, AttestationValidationError>
    where T: ClientDB + Sized
{
    // TODO: assert attestion isn't already known

    /*
     * The attesation slot must not be higher than the block that contained it.
     */
    if a.slot > block_slot {
        return Err(AttestationValidationError::SlotTooHigh);
    }

    /*
     * The slot of this attestation must not be more than cycle_length + 1 distance
     * from the block that contained it.
     *
     * The below code stays overflow-safe as long as cycle length is a < 64 bit integer.
     */
    if a.slot < block_slot.saturating_sub(u64::from(cycle_length) + 1) {
        return Err(AttestationValidationError::SlotTooLow);
    }

    /*
     * The attestation must indicate that its last justified slot is the same as the last justified
     * slot known to us.
     */
    if a.justified_slot > known_last_justified_slot {
        return Err(AttestationValidationError::JustifiedSlotTooHigh);
    }

    /*
     * There is no need to include more oblique parents hashes than there are blocks
     * in a cycle.
     */
    if a.oblique_parent_hashes.len() > usize::from(cycle_length) {
        return Err(AttestationValidationError::TooManyObliqueHashes);
    }

    /*
     * Retrieve the set of attestation indices for this slot and shard id.
     *
     * This is an array mapping the order that validators will appear in the bitfield to the
     * canonincal index of a validator.
     */
    let attestation_indices = attester_map.get(&(a.slot, a.shard_id.into()))
        .ok_or(AttestationValidationError::BadAttesterMap)?;

    /*
     * The bitfield must be no longer than the minimum required to represent each validator in the
     * attestation indicies for this slot and shard id.
     */
    if a.attester_bitfield.num_bytes() !=
        bytes_for_bits(attestation_indices.len())
    {
        return Err(AttestationValidationError::IncorrectBitField);
    }

    /*
     * If there are excess bits in the bitfield because the number of a validators in not a
     * multiple of 8, reject this attestation record.
     *
     * Allow extra set bits would permit mutliple different byte layouts (and therefore hashes) to
     * refer to the same AttesationRecord.
     */
    let last_byte =
        a.attester_bitfield.get_byte(a.attester_bitfield.num_bytes())
        .ok_or(AttestationValidationError::IncorrectBitField)?;
    if any_of_last_n_bits_are_set(last_byte, a.attester_bitfield.len() % 8) {
        return Err(AttestationValidationError::IncorrectBitField)
    }

    /*
     * The specified justified block hash must be known to us
     */
    if !block_store.block_exists(&a.justified_block_hash)? {
        return Err(AttestationValidationError::UnknownJustifiedBlock)
    }

    let signed_message = {
        let parent_hashes = attestation_parent_hashes(
            cycle_length,
            block_slot,
            a.slot,
            &known_parent_hashes,
            &a.oblique_parent_hashes)?;
        generate_signed_message(
            a.slot,
            &parent_hashes,
            a.shard_id,
            &a.shard_block_hash,
            a.justified_slot)
    };

    let voted_hashmap =
        verify_aggregate_signature_for_indices(
            &signed_message,
            &a.aggregate_sig,
            &attestation_indices,
            &a.attester_bitfield,
            &validator_store)?;

    Ok(voted_hashmap)
}

/// Generates the message used to validate the signature provided with an AttestationRecord.
///
/// Ensures that the signer of the message has a view of the chain that is compatible with ours.
fn generate_signed_message(slot: u64,
                           parent_hashes: &[Hash256],
                           shard_id: u16,
                           shard_block_hash: &Hash256,
                           justified_slot: u64)
    -> Vec<u8>
{
    /*
     * Note: it's a little risky here to use SSZ, because the encoding is not necessarily SSZ
     * (for example, SSZ might change whilst this doesn't).
     *
     * I have suggested switching this to ssz here:
     * https://github.com/ethereum/eth2.0-specs/issues/5
     *
     * If this doesn't happen, it would be safer to not use SSZ at all.
     */
    let mut ssz_stream = SszStream::new();
    ssz_stream.append(&slot);
    for h in parent_hashes {
        ssz_stream.append_encoded_raw(&h.to_vec())
    }
    ssz_stream.append(&shard_id);
    ssz_stream.append(shard_block_hash);
    ssz_stream.append(&justified_slot);
    let bytes = ssz_stream.drain();
    canonical_hash(&bytes)
}

impl From<ParentHashesError> for AttestationValidationError {
    fn from(e: ParentHashesError) -> Self {
        match e {
            ParentHashesError::BadCurrentHashes
                => AttestationValidationError::BadCurrentHashes,
            ParentHashesError::BadObliqueHashes
                => AttestationValidationError::BadObliqueHashes,
            ParentHashesError::SlotTooLow
                => AttestationValidationError::SlotTooLow,
            ParentHashesError::SlotTooHigh
                => AttestationValidationError::SlotTooHigh,
            ParentHashesError::IntWrapping
                => AttestationValidationError::IntWrapping
        }
    }
}

impl From<DBError> for AttestationValidationError {
    fn from(e: DBError) -> Self {
        AttestationValidationError::DBError(e.message)
    }
}

impl From<SignatureVerificationError> for AttestationValidationError {
    fn from(e: SignatureVerificationError) -> Self {
        match e {
            SignatureVerificationError::BadValidatorIndex
                => AttestationValidationError::BadAttesterMap,
            SignatureVerificationError::PublicKeyCorrupt
                => AttestationValidationError::PublicKeyCorrupt,
            SignatureVerificationError::NoPublicKeyForValidator
                => AttestationValidationError::NoPublicKeyForValidator,
            SignatureVerificationError::DBError(s)
                => AttestationValidationError::DBError(s),
        }
    }
}
<|endoftext|>


<commit_before>use rustc::hir;
use rustc::lint::*;
use rustc::ty;
use syntax::codemap::Span;
use utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use utils::paths;

#[derive(Clone)]
pub struct Pass;

/// **What it does:** Checks for usage of `Option.map(f)` where f is a function
/// or closure that returns the unit type.
///
/// **Why is this bad?** Readability, this can be written more clearly with
/// an if statement
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x: Option<&str> = do_stuff();
/// x.map(log_err_msg);
/// x.map(|msg| log_err_msg(format_msg(msg)))
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x: Option<&str> = do_stuff();
/// if let Some(msg) = x {
///     log_err_msg(msg)
/// }
/// if let Some(msg) = x {
///     log_err_msg(format_msg(msg))
/// }
/// ```
declare_clippy_lint! {
    pub OPTION_MAP_UNIT_FN,
    complexity,
    "using `Option.map(f)`, where f is a function or closure that returns ()"
}

/// **What it does:** Checks for usage of `Result.map(f)` where f is a function
/// or closure that returns the unit type.
///
/// **Why is this bad?** Readability, this can be written more clearly with
/// an if statement
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x: Result<&str, &str> = do_stuff();
/// x.map(log_err_msg);
/// x.map(|msg| log_err_msg(format_msg(msg)))
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x: Result<&str, &str> = do_stuff();
/// if let Ok(msg) = x {
///     log_err_msg(msg)
/// }
/// if let Ok(msg) = x {
///     log_err_msg(format_msg(msg))
/// }
/// ```
declare_clippy_lint! {
    pub RESULT_MAP_UNIT_FN,
    complexity,
    "using `Result.map(f)`, where f is a function or closure that returns ()"
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN)
    }
}

fn is_unit_type(ty: ty::Ty) -> bool {
    match ty.sty {
        ty::TyTuple(slice) => slice.is_empty(),
        ty::TyNever => true,
        _ => false,
    }
}

fn is_unit_function(cx: &LateContext, expr: &hir::Expr) -> bool {
    let ty = cx.tables.expr_ty(expr);

    if let ty::TyFnDef(id, _) = ty.sty {
        if let Some(fn_type) = cx.tcx.fn_sig(id).no_late_bound_regions() {
            return is_unit_type(fn_type.output());
        }
    }
    false
}

fn is_unit_expression(cx: &LateContext, expr: &hir::Expr) -> bool {
    is_unit_type(cx.tables.expr_ty(expr))
}

/// The expression inside a closure may or may not have surrounding braces and
/// semicolons, which causes problems when generating a suggestion. Given an
/// expression that evaluates to '()' or '!', recursively remove useless braces
/// and semi-colons until is suitable for including in the suggestion template
fn reduce_unit_expression<'a>(cx: &LateContext, expr: &'a hir::Expr) -> Option<Span> {
    if !is_unit_expression(cx, expr) {
        return None;
    }

    match expr.node {
        hir::ExprCall(_, _) |
        hir::ExprMethodCall(_, _, _) => {
            // Calls can't be reduced any more
            Some(expr.span)
        },
        hir::ExprBlock(ref block) => {
            match (&block.stmts[..], block.expr.as_ref()) {
                (&[], Some(inner_expr)) => {
                    // If block only contains an expression,
                    // reduce `{ X }` to `X`
                    reduce_unit_expression(cx, inner_expr)
                },
                (&[ref inner_stmt], None) => {
                    // If block only contains statements,
                    // reduce `{ X; }` to `X` or `X;`
                    match inner_stmt.node {
                        hir::StmtDecl(ref d, _) => Some(d.span),
                        hir::StmtExpr(ref e, _) => Some(e.span),
                        hir::StmtSemi(_, _) => Some(inner_stmt.span),
                    }
                },
                _ => {
                    // For closures that contain multiple statements
                    // it's difficult to get a correct suggestion span
                    // for all cases (multi-line closures specifically)
                    //
                    // We do not attempt to build a suggestion for those right now.
                    None
                }
            }
        },
        _ => None,
    }
}

fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Option<(&'tcx hir::Arg, &'a hir::Expr)> {
    if let hir::ExprClosure(_, ref decl, inner_expr_id, _, _) = expr.node {
        let body = cx.tcx.hir.body(inner_expr_id);
        let body_expr = &body.value;

        if_chain! {
            if decl.inputs.len() == 1;
            if is_unit_expression(cx, body_expr);
            if let Some(binding) = iter_input_pats(&decl, body).next();
            then {
                return Some((binding, body_expr));
            }
        }
    }
    None
}

/// Builds a name for the let binding variable (var_arg)
///
/// `x.field` => `x_field`
/// `y` => `_y`
///
/// Anything else will return `_`.
fn let_binding_name(cx: &LateContext, var_arg: &hir::Expr) -> String {
    match &var_arg.node {
        hir::ExprField(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
        hir::ExprPath(_) => format!("_{}", snippet(cx, var_arg.span, "")),
        _ => "_".to_string()
    }
}

fn suggestion_msg(function_type: &str, map_type: &str) -> String {
    format!(
        "called `map(f)` on an {0} value where `f` is a unit {1}",
        map_type,
        function_type
    )
}

fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) {
    let var_arg = &map_args[0];
    let fn_arg = &map_args[1];

    let (map_type, variant, lint) =
        if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
            ("Option", "Some", OPTION_MAP_UNIT_FN)
        } else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
            ("Result", "Ok", RESULT_MAP_UNIT_FN)
        } else {
            return
        };

    if is_unit_function(cx, fn_arg) {
        let msg = suggestion_msg("function", map_type);
        let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}",
                                 variant,
                                 let_binding_name(cx, var_arg),
                                 snippet(cx, var_arg.span, "_"),
                                 snippet(cx, fn_arg.span, "_"));

        span_lint_and_then(cx, lint, expr.span, &msg, |db| {
            db.span_approximate_suggestion(stmt.span, "try this", suggestion);
        });
    } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
        let msg = suggestion_msg("closure", map_type);

        enum Suggestion {
            Full(String),
            Approx(String)
        }

        let suggestion = if let Some(expr_span) = reduce_unit_expression(cx, closure_expr) {
            Suggestion::Full(
                format!("if let {0}({1}) = {2} {{ {3} }}",
                        variant,
                        snippet(cx, binding.pat.span, "_"),
                        snippet(cx, var_arg.span, "_"),
                        snippet(cx, expr_span, "_"))
            )
        } else {
            Suggestion::Approx(
                format!("if let {0}({1}) = {2} {{ ... }}",
                        variant,
                        snippet(cx, binding.pat.span, "_"),
                        snippet(cx, var_arg.span, "_"))
            )
        };

        span_lint_and_then(cx, lint, expr.span, &msg, |db| {
            match suggestion {
                Suggestion::Full(sugg) => db.span_suggestion(stmt.span, "try this", sugg),
                Suggestion::Approx(sugg) => db.span_approximate_suggestion(stmt.span, "try this", sugg),
            };
        });
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_stmt(&mut self, cx: &LateContext, stmt: &hir::Stmt) {
        if in_macro(stmt.span) {
            return;
        }

        if let hir::StmtSemi(ref expr, _) = stmt.node {
            if let hir::ExprMethodCall(_, _, _) = expr.node {
                if let Some(arglists) = method_chain_args(expr, &["map"]) {
                    lint_map_unit_fn(cx, stmt, expr, arglists[0]);
                }
            }
        }
    }
}
<commit_msg>Refactor out enum and address nits<commit_after>use rustc::hir;
use rustc::lint::*;
use rustc::ty;
use syntax::codemap::Span;
use utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use utils::paths;

#[derive(Clone)]
pub struct Pass;

/// **What it does:** Checks for usage of `option.map(f)` where f is a function
/// or closure that returns the unit type.
///
/// **Why is this bad?** Readability, this can be written more clearly with
/// an if let statement
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x: Option<&str> = do_stuff();
/// x.map(log_err_msg);
/// x.map(|msg| log_err_msg(format_msg(msg)))
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x: Option<&str> = do_stuff();
/// if let Some(msg) = x {
///     log_err_msg(msg)
/// }
/// if let Some(msg) = x {
///     log_err_msg(format_msg(msg))
/// }
/// ```
declare_clippy_lint! {
    pub OPTION_MAP_UNIT_FN,
    complexity,
    "using `option.map(f)`, where f is a function or closure that returns ()"
}

/// **What it does:** Checks for usage of `result.map(f)` where f is a function
/// or closure that returns the unit type.
///
/// **Why is this bad?** Readability, this can be written more clearly with
/// an if let statement
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x: Result<&str, &str> = do_stuff();
/// x.map(log_err_msg);
/// x.map(|msg| log_err_msg(format_msg(msg)))
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x: Result<&str, &str> = do_stuff();
/// if let Ok(msg) = x {
///     log_err_msg(msg)
/// }
/// if let Ok(msg) = x {
///     log_err_msg(format_msg(msg))
/// }
/// ```
declare_clippy_lint! {
    pub RESULT_MAP_UNIT_FN,
    complexity,
    "using `result.map(f)`, where f is a function or closure that returns ()"
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN)
    }
}

fn is_unit_type(ty: ty::Ty) -> bool {
    match ty.sty {
        ty::TyTuple(slice) => slice.is_empty(),
        ty::TyNever => true,
        _ => false,
    }
}

fn is_unit_function(cx: &LateContext, expr: &hir::Expr) -> bool {
    let ty = cx.tables.expr_ty(expr);

    if let ty::TyFnDef(id, _) = ty.sty {
        if let Some(fn_type) = cx.tcx.fn_sig(id).no_late_bound_regions() {
            return is_unit_type(fn_type.output());
        }
    }
    false
}

fn is_unit_expression(cx: &LateContext, expr: &hir::Expr) -> bool {
    is_unit_type(cx.tables.expr_ty(expr))
}

/// The expression inside a closure may or may not have surrounding braces and
/// semicolons, which causes problems when generating a suggestion. Given an
/// expression that evaluates to '()' or '!', recursively remove useless braces
/// and semi-colons until is suitable for including in the suggestion template
fn reduce_unit_expression<'a>(cx: &LateContext, expr: &'a hir::Expr) -> Option<Span> {
    if !is_unit_expression(cx, expr) {
        return None;
    }

    match expr.node {
        hir::ExprCall(_, _) |
        hir::ExprMethodCall(_, _, _) => {
            // Calls can't be reduced any more
            Some(expr.span)
        },
        hir::ExprBlock(ref block) => {
            match (&block.stmts[..], block.expr.as_ref()) {
                (&[], Some(inner_expr)) => {
                    // If block only contains an expression,
                    // reduce `{ X }` to `X`
                    reduce_unit_expression(cx, inner_expr)
                },
                (&[ref inner_stmt], None) => {
                    // If block only contains statements,
                    // reduce `{ X; }` to `X` or `X;`
                    match inner_stmt.node {
                        hir::StmtDecl(ref d, _) => Some(d.span),
                        hir::StmtExpr(ref e, _) => Some(e.span),
                        hir::StmtSemi(_, _) => Some(inner_stmt.span),
                    }
                },
                _ => {
                    // For closures that contain multiple statements
                    // it's difficult to get a correct suggestion span
                    // for all cases (multi-line closures specifically)
                    //
                    // We do not attempt to build a suggestion for those right now.
                    None
                }
            }
        },
        _ => None,
    }
}

fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Option<(&'tcx hir::Arg, &'a hir::Expr)> {
    if let hir::ExprClosure(_, ref decl, inner_expr_id, _, _) = expr.node {
        let body = cx.tcx.hir.body(inner_expr_id);
        let body_expr = &body.value;

        if_chain! {
            if decl.inputs.len() == 1;
            if is_unit_expression(cx, body_expr);
            if let Some(binding) = iter_input_pats(&decl, body).next();
            then {
                return Some((binding, body_expr));
            }
        }
    }
    None
}

/// Builds a name for the let binding variable (var_arg)
///
/// `x.field` => `x_field`
/// `y` => `_y`
///
/// Anything else will return `_`.
fn let_binding_name(cx: &LateContext, var_arg: &hir::Expr) -> String {
    match &var_arg.node {
        hir::ExprField(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
        hir::ExprPath(_) => format!("_{}", snippet(cx, var_arg.span, "")),
        _ => "_".to_string()
    }
}

fn suggestion_msg(function_type: &str, map_type: &str) -> String {
    format!(
        "called `map(f)` on an {0} value where `f` is a unit {1}",
        map_type,
        function_type
    )
}

fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) {
    let var_arg = &map_args[0];
    let fn_arg = &map_args[1];

    let (map_type, variant, lint) =
        if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
            ("Option", "Some", OPTION_MAP_UNIT_FN)
        } else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
            ("Result", "Ok", RESULT_MAP_UNIT_FN)
        } else {
            return
        };

    if is_unit_function(cx, fn_arg) {
        let msg = suggestion_msg("function", map_type);
        let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}",
                                 variant,
                                 let_binding_name(cx, var_arg),
                                 snippet(cx, var_arg.span, "_"),
                                 snippet(cx, fn_arg.span, "_"));

        span_lint_and_then(cx, lint, expr.span, &msg, |db| {
            db.span_approximate_suggestion(stmt.span, "try this", suggestion);
        });
    } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
        let msg = suggestion_msg("closure", map_type);

        span_lint_and_then(cx, lint, expr.span, &msg, |db| {
            if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
                let suggestion = format!("if let {0}({1}) = {2} {{ {3} }}",
                                        variant,
                                        snippet(cx, binding.pat.span, "_"),
                                        snippet(cx, var_arg.span, "_"),
                                        snippet(cx, reduced_expr_span, "_"));
                db.span_suggestion(stmt.span, "try this", suggestion);
            } else {
                let suggestion = format!("if let {0}({1}) = {2} {{ ... }}",
                                        variant,
                                        snippet(cx, binding.pat.span, "_"),
                                        snippet(cx, var_arg.span, "_"));
                db.span_approximate_suggestion(stmt.span, "try this", suggestion);
            }
        });
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_stmt(&mut self, cx: &LateContext, stmt: &hir::Stmt) {
        if in_macro(stmt.span) {
            return;
        }

        if let hir::StmtSemi(ref expr, _) = stmt.node {
            if let hir::ExprMethodCall(_, _, _) = expr.node {
                if let Some(arglists) = method_chain_args(expr, &["map"]) {
                    lint_map_unit_fn(cx, stmt, expr, arglists[0]);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::{Arc, Once},
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, Lazy, OneShot, Result};

static BLOCKING_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);
static IO_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);
static SNAPSHOT_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);

type Work = Box<dyn FnOnce() + Send + 'static>;

#[derive(Default)]
struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

#[allow(unsafe_code)]
unsafe impl Send for Queue {}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            let res = self.cv.wait_until(&mut queue, cutoff);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }

    fn perform_work(&self) {
        let wait_limit = Duration::from_millis(100);

        loop {
            let guard = crate::pin();
            guard.flush();
            drop(guard);
            debug_delay();
            let task_res = self.recv_timeout(wait_limit);

            if let Some(task) = task_res {
                //println!("starting work");
                (task)();
                //println!("done work");
            }
        }
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    spawn_to(work, &BLOCKING_QUEUE)
}

#[cfg(all(
    not(miri),
    any(
        windows,
        target_os = "linux",
        target_os = "macos",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd",
    )
))]
fn spawn_to<F, R>(work: F, queue: &'static Queue) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    static START_THREADS: Once = Once::new();

    START_THREADS.call_once(|| {
        std::thread::Builder::new()
            .name("sled-io-thread".into())
            .spawn(|| IO_QUEUE.perform_work())
            .expect("failed to spawn critical IO thread");

        std::thread::Builder::new()
            .name("sled-blocking-thread".into())
            .spawn(|| BLOCKING_QUEUE.perform_work())
            .expect("failed to spawn critical blocking thread");

        std::thread::Builder::new()
            .name("sled-snapshot-thread".into())
            .spawn(|| SNAPSHOT_QUEUE.perform_work())
            .expect("failed to spawn critical snapshot thread");
    });

    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        promise_filler.fill((work)());
    };

    queue.send(Box::new(task));

    Ok(promise)
}

#[cfg(any(
    miri,
    not(any(
        windows,
        target_os = "linux",
        target_os = "macos",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd",
    ))
))]
pub fn spawn_to<F, R>(work: F, _: &'static Queue) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    // Polyfill for platforms other than those we explicitly trust to
    // perform threaded work on. Just execute a task without involving threads.
    let (promise_filler, promise) = OneShot::pair();
    promise_filler.fill((work)());
    Ok(promise)
}

pub fn truncate(
    config: crate::RunningConfig,
    at: u64,
) -> Result<OneShot<Result<()>>> {
    spawn_to(
        move || {
            log::debug!("truncating file to length {}", at);
            config
                .file
                .set_len(at)
                .and_then(|_| config.file.sync_all())
                .map_err(|e| e.into())
        },
        &IO_QUEUE,
    )
}

pub fn take_fuzzy_snapshot(
    pc: crate::pagecache::PageCache,
) -> Result<OneShot<()>> {
    spawn_to(
        move || {
            if let Err(e) = pc.take_fuzzy_snapshot() {
                log::error!("failed to write snapshot: {:?}", e);
            }
        },
        &SNAPSHOT_QUEUE,
    )
}

pub(crate) fn write_to_log(
    iobuf: Arc<crate::pagecache::iobuf::IoBuf>,
    iobufs: Arc<crate::pagecache::iobuf::IoBufs>,
) -> Result<OneShot<()>> {
    spawn_to(
        move || {
            if let Err(e) = iobufs.write_to_log(&iobuf) {
                log::error!(
                    "hit error while writing iobuf with lsn {}: {:?}",
                    iobuf.lsn,
                    e
                );

                // store error before notifying so that waiting threads will see
                // it
                iobufs.config.set_global_error(e);

                let intervals = iobufs.intervals.lock();

                // having held the mutex makes this linearized
                // with the notify below.
                drop(intervals);

                let _notified = iobufs.interval_updated.notify_all();
            }
        },
        &IO_QUEUE,
    )
}
<commit_msg>Fix typo<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::{Arc, Once},
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, Lazy, OneShot, Result};

static BLOCKING_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);
static IO_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);
static SNAPSHOT_QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(Default::default);

type Work = Box<dyn FnOnce() + Send + 'static>;

#[derive(Default)]
struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

#[allow(unsafe_code)]
unsafe impl Send for Queue {}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            let res = self.cv.wait_until(&mut queue, cutoff);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }

    fn perform_work(&self) {
        let wait_limit = Duration::from_millis(100);

        loop {
            let guard = crate::pin();
            guard.flush();
            drop(guard);
            debug_delay();
            let task_res = self.recv_timeout(wait_limit);

            if let Some(task) = task_res {
                //println!("starting work");
                (task)();
                //println!("done work");
            }
        }
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    spawn_to(work, &BLOCKING_QUEUE)
}

#[cfg(all(
    not(miri),
    any(
        windows,
        target_os = "linux",
        target_os = "macos",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd",
    )
))]
fn spawn_to<F, R>(work: F, queue: &'static Queue) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    static START_THREADS: Once = Once::new();

    START_THREADS.call_once(|| {
        std::thread::Builder::new()
            .name("sled-io-thread".into())
            .spawn(|| IO_QUEUE.perform_work())
            .expect("failed to spawn critical IO thread");

        std::thread::Builder::new()
            .name("sled-blocking-thread".into())
            .spawn(|| BLOCKING_QUEUE.perform_work())
            .expect("failed to spawn critical blocking thread");

        std::thread::Builder::new()
            .name("sled-snapshot-thread".into())
            .spawn(|| SNAPSHOT_QUEUE.perform_work())
            .expect("failed to spawn critical snapshot thread");
    });

    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        promise_filler.fill((work)());
    };

    queue.send(Box::new(task));

    Ok(promise)
}

#[cfg(any(
    miri,
    not(any(
        windows,
        target_os = "linux",
        target_os = "macos",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd",
    ))
))]
pub fn spawn_to<F, R>(work: F, _: &'static Queue) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    // Polyfill for platforms other than those we explicitly trust to
    // perform threaded work on. Just execute a task without involving threads.
    let (promise_filler, promise) = OneShot::pair();
    promise_filler.fill((work)());
    Ok(promise)
}

pub fn truncate(
    config: crate::RunningConfig,
    at: u64,
) -> Result<OneShot<Result<()>>> {
    spawn_to(
        move || {
            log::debug!("truncating file to length {}", at);
            config
                .file
                .set_len(at)
                .and_then(|_| config.file.sync_all())
                .map_err(|e| e.into())
        },
        &IO_QUEUE,
    )
}

pub fn take_fuzzy_snapshot(
    pc: crate::pagecache::PageCache,
) -> Result<OneShot<()>> {
    spawn_to(
        move || {
            if let Err(e) = pc.take_fuzzy_snapshot() {
                log::error!("failed to write snapshot: {:?}", e);
            }
        },
        &SNAPSHOT_QUEUE,
    )
}

pub(crate) fn write_to_log(
    iobuf: Arc<crate::pagecache::iobuf::IoBuf>,
    iobufs: Arc<crate::pagecache::iobuf::IoBufs>,
) -> Result<OneShot<()>> {
    spawn_to(
        move || {
            let lsn = iobuf.lsn;
            if let Err(e) = iobufs.write_to_log(iobuf) {
                log::error!(
                    "hit error while writing iobuf with lsn {}: {:?}",
                    lsn,
                    e
                );

                // store error before notifying so that waiting threads will see
                // it
                iobufs.config.set_global_error(e);

                let intervals = iobufs.intervals.lock();

                // having held the mutex makes this linearized
                // with the notify below.
                drop(intervals);

                let _notified = iobufs.interval_updated.notify_all();
            }
        },
        &IO_QUEUE,
    )
}
<|endoftext|>


<commit_before>use std::rc::*;

use super::treenode::*;
use super::tree_ref::*;

pub trait TreeNodeBuilder {
    ///
    /// Sets the children of a tree node to a set of tree node references
    ///
    fn set_children_refs<'a>(&mut self, new_children: &'a Vec<Rc<TreeNode>>);
}

type ChildList = Rc<Vec<Rc<TreeNode>>>;

impl<T: MutableTreeNode> TreeNodeBuilder for T {
    fn set_children_refs<'a>(&mut self, new_children: &'a Vec<Rc<TreeNode>>) {
        let num_new_children = new_children.len();

        if num_new_children > 0 {
            // Build the final child node backwards
            let mut new_child = new_children[num_new_children-1].with_no_sibling();

            for child_num in (0..(num_new_children-1)).rev() {
                new_child = new_children[child_num].with_sibling_ref(&new_child);
            }

            self.set_child(new_child);
        } else {
            // No children
            self.clear_child();
        }
    }
}

///
/// Macro that will create a tree from a set of expressions that support the ToTreeNode trait
///
/// The first parameter is the root item, followed by the child items
///
macro_rules! tree {
    ( $root: expr, $( $child: expr ), * ) => {
        {
            use std::rc::*;

            let mut root        = BasicTree::from($root);
            let mut child_list  = Vec::new();

            $(
                child_list.push($child.to_tree_node());
            )*

            root.set_children_refs(&child_list);

            let result: Rc<TreeNode> = Rc::new(root);
            result
        }
    }
}

#[cfg(test)]
mod treenode_builder_tests {
    use super::super::treenode::*;
    use super::super::basictree::*;

    #[test]
    fn can_build_tree() {
        let mut root = BasicTree::new("test", ());
        let child_list = vec!["child1".to_tree_node(), "child2".to_tree_node(), "child3".to_tree_node()];

        root.set_children_refs(&child_list);

        assert!(root.get_child_ref().is_some());
        assert!(root.get_child_ref_at(0).map(|x| x.get_tag() == "child1").unwrap_or(false));
        assert!(root.get_child_ref_at(1).map(|x| x.get_tag() == "child2").unwrap_or(false));
        assert!(root.get_child_ref_at(2).map(|x| x.get_tag() == "child3").unwrap_or(false));
        assert!(root.get_child_ref_at(3).is_none());
    }

    #[test]
    fn can_build_tree_macro() {
        let root = tree!("root", "child1", ("child2", "value"), tree!("child3", "grandchild1"));

        assert!(root.get_child_ref().is_some());
        assert!(root.get_child_ref_at(0).map(|x| x.get_tag() == "child1").unwrap_or(false));
        assert!(root.get_child_ref_at(1).map(|x| x.get_tag() == "child2").unwrap_or(false));
        assert!(root.get_child_ref_at(2).map(|x| x.get_tag() == "child3").unwrap_or(false));
        assert!(root.get_child_ref_at(2).and_then(|x| x.get_child_ref_at(0)).map(|x| x.get_tag() == "grandchild1").unwrap_or(false));
        assert!(root.get_child_ref_at(3).is_none());
    }
}
<commit_msg>Change the builder to make direct copies of the tree nodes instead of using TreeRefs<commit_after>use std::rc::*;

use super::treenode::*;
use super::basictree::*;

pub trait TreeNodeBuilder {
    ///
    /// Sets the children of a tree node to a set of tree node references
    ///
    fn set_children_refs<'a>(&mut self, new_children: &'a Vec<Rc<TreeNode>>);
}

type ChildList = Rc<Vec<Rc<TreeNode>>>;

impl<T: MutableTreeNode> TreeNodeBuilder for T {
    fn set_children_refs<'a>(&mut self, new_children: &'a Vec<Rc<TreeNode>>) {
        let num_new_children = new_children.len();

        if num_new_children > 0 {
            // Build the list of child nodes backwards
            let mut new_child = Rc::new(BasicTree::from(&new_children[num_new_children-1]));
            new_child.clear_sibling();

            for child_num in (0..(num_new_children-1)).rev() {
                let previous_child = Rc::new(BasicTree::from(&new_children[child_num]));
                previous_child.set_sibling_ref(new_child);

                new_child = previous_child;
            }

            self.set_child(new_child);
        } else {
            // No children
            self.clear_child();
        }
    }
}

///
/// Macro that will create a tree from a set of expressions that support the ToTreeNode trait
///
/// The first parameter is the root item, followed by the child items
///
macro_rules! tree {
    ( $root: expr, $( $child: expr ), * ) => {
        {
            use std::rc::*;

            let mut root        = BasicTree::from($root);
            let mut child_list  = Vec::new();

            $(
                child_list.push($child.to_tree_node());
            )*

            root.set_children_refs(&child_list);

            let result: Rc<TreeNode> = Rc::new(root);
            result
        }
    }
}

#[cfg(test)]
mod treenode_builder_tests {
    use super::super::treenode::*;
    use super::super::basictree::*;

    #[test]
    fn can_build_tree() {
        let mut root = BasicTree::new("test", ());
        let child_list = vec!["child1".to_tree_node(), "child2".to_tree_node(), "child3".to_tree_node()];

        root.set_children_refs(&child_list);

        assert!(root.get_child_ref().is_some());
        assert!(root.get_child_ref_at(0).map(|x| x.get_tag() == "child1").unwrap_or(false));
        assert!(root.get_child_ref_at(1).map(|x| x.get_tag() == "child2").unwrap_or(false));
        assert!(root.get_child_ref_at(2).map(|x| x.get_tag() == "child3").unwrap_or(false));
        assert!(root.get_child_ref_at(3).is_none());
    }

    #[test]
    fn can_build_tree_macro() {
        let root = tree!("root", "child1", ("child2", "value"), tree!("child3", "grandchild1"));

        assert!(root.get_child_ref().is_some());
        assert!(root.get_child_ref_at(0).map(|x| x.get_tag() == "child1").unwrap_or(false));
        assert!(root.get_child_ref_at(1).map(|x| x.get_tag() == "child2").unwrap_or(false));
        assert!(root.get_child_ref_at(2).map(|x| x.get_tag() == "child3").unwrap_or(false));
        assert!(root.get_child_ref_at(2).and_then(|x| x.get_child_ref_at(0)).map(|x| x.get_tag() == "grandchild1").unwrap_or(false));
        assert!(root.get_child_ref_at(3).is_none());
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::fmt::{self, Write};
use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};

/// The Message Builder is an ergonomic utility to easily build a message,
/// by adding text and mentioning mentionable structs.
///
/// The finalized value can be accessed via [`build`] or the inner value.
///
/// # Examples
///
/// Build a message, mentioning a [`user`] and an [`emoji`], and retrieving the
/// value:
///
/// ```rust,ignore
/// use serenity::utils::MessageBuilder;
///
/// // assuming an `emoji` and `user` have already been bound
///
/// let content = MessageBuilder::new()
///     .push("You sent a message, ")
///     .mention(user)
///     .push("! ")
///     .mention(emoji)
///     .build();
/// ```
///
/// [`build`]: #method.build
/// [`emoji`]: #method.emoji
/// [`user`]: #method.user

fn normalize(text: &str) -> String {
    // Remove everyone and here mentions
    // This changes 'at' symbol to a full-width variation
    text.replace("@everyone", "＠everyone")
        .replace("@here", "＠here")
        // Remove invite links and popular scam websites, mostly to prevent the
        // current user from triggering various ad detectors
        .replace("discord.gg", "discord․gg")
        .replace("discord.me", "discord․me")
        .replace("discordlist.net", "discordlist․net")
        .replace("discordservers.com", "discordservers․com")
        .replace("discordapp.com/invite", "discordapp․com/invite")
        // Remove right-to-left and other similar overrides
        .replace('\u{202E}', " ") // RTL
        .replace('\u{200F}', " ") // RTL Mark
        .replace('\u{202B}', " ") // RTL Embedding
        .replace('\u{200B}', " ") // Zero-width space
        .replace('\u{200D}', " ") // Zero-width joiner
        .replace('\u{200C}', " ") // Zero-width non-joiner
}

pub struct MessageBuilder(pub String);

impl MessageBuilder {
    /// Creates a new, empty-content builder.
    pub fn new() -> MessageBuilder {
        MessageBuilder::default()
    }

    /// Pulls the inner value out of the builder.
    ///
    /// # Examples
    ///
    /// This is equivilant to simply retrieving the tuple struct's first value:
    ///
    /// ```rust
    /// use serenity::utils::MessageBuilder;
    ///
    /// let content = MessageBuilder::new().push("test").0;
    ///
    /// assert_eq!(content, "test");
    /// ```
    pub fn build(self) -> String {
        self.0
    }

    /// Mentions the [`GuildChannel`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`ChannelId`]. Refer to
    /// `ChannelId`'s documentation for more information.
    ///
    /// Refer to `ChannelId`'s [Display implementation] for more information on
    /// how this is formatted.
    ///
    /// [`ChannelId`]: ../model/struct.ChannelId.html
    /// [`GuildChannel`]: ../model/struct.GuildChannel.html
    /// [Display implementation]: ../model/struct.ChannelId.html#method.fmt-1
    pub fn channel<C: Into<ChannelId>>(mut self, channel: C) -> Self {
        let _ = write!(self.0, "{}", channel.into());

        self
    }

    /// Displays the given emoji in the built message.
    ///
    /// Refer to `Emoji`s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [Display implementation]: ../model/struct.Emoji.html#method.fmt
    pub fn emoji(mut self, emoji: Emoji) -> Self {
        let _ = write!(self.0, "{}", emoji);

        self
    }

    /// Mentions something that implements the [`Mentionable`] trait.
    ///
    /// [`Mentionable`]: ../model/trait.Mentionable.html
    pub fn mention<M: Mentionable>(mut self, item: M) -> Self {
        let _ = write!(self.0, "{}", item.mention());

        self
    }

    /// Pushes a string to the internal message content.
    ///
    /// Note that this does not mutate either the given data or the internal
    /// message content in anyway prior to appending the given content to the
    /// internal message.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::MessageBuilder;
    ///
    /// let message = MessageBuilder::new().push("test");
    ///
    /// assert_eq!(message.push("ing").0, "testing");
    /// ```
    pub fn push(mut self, content: &str) -> Self {
        self.0.push_str(content);

        self
    }

    /// Pushes a code-block to your message, with optional syntax highlighting.
    pub fn push_codeblock(mut self, content: &str, language: Option<&str>) -> Self {
        self.0.push_str("```");

        if let Some(language) = language {
            self.0.push_str(language);
        }

        self.0.push('\n');
        self.0.push_str(content);
        self.0.push_str("\n```");

        self
    }

    /// Pushes an inline monospaced text to your message.
    pub fn push_mono(mut self, content: &str) -> Self {
        self.0.push('`');
        self.0.push_str(content);
        self.0.push('`');

        self
    }

    /// Pushes an inline italicized text to your message.
    pub fn push_italic(mut self, content: &str) -> Self {
        self.0.push('_');
        self.0.push_str(content);
        self.0.push('_');

        self
    }

    /// Pushes an inline bold text to your message.
    pub fn push_bold(mut self, content: &str) -> Self {
        self.0.push_str("**");
        self.0.push_str(content);
        self.0.push_str("**");

        self
    }

    /// Pushes an underlined inline text to your message.
    pub fn push_underline(mut self, content: &str) -> Self {
        self.0.push_str("__");
        self.0.push_str(content);
        self.0.push_str("__");

        self
    }

    /// Pushes a strikethrough inline text to your message.
    pub fn push_strike(mut self, content: &str) -> Self {
        self.0.push_str("~~");
        self.0.push_str(content);
        self.0.push_str("~~");

        self
    }

    /// Pushes text to your message, but normalizing content - that means
    /// ensuring that there's no unwanted formatting, mention spam etc.
    pub fn push_safe(mut self, content: &str) -> Self {
        let normalized = normalize(content)
            .replace('*', "\\*")
            .replace('`', "\\`")
            .replace('_', "\\_");

        self.0.push_str(&normalized);

        self
    }

    /// Pushes a code-block to your message normalizing content.
    pub fn push_codeblock_safe(mut self, content: &str, language: Option<&str>)
        -> Self {
        let content = &normalize(content)
            .replace("```", "\u{201B}\u{201B}\u{201B}");

        self.0.push_str("```");

        if let Some(language) = language {
            self.0.push_str(language);
        }

        self.0.push('\n');
        self.0.push_str(content);
        self.0.push_str("```");

        self
    }

    /// Pushes an inline monospaced text to your message normalizing content.
    pub fn push_mono_safe(mut self, content: &str) -> Self {
        self.0.push('`');
        self.0.push_str(&normalize(content).replace("`", "\u{201B}"));
        self.0.push('`');

        self
    }

    /// Pushes an inline italicized text to your message normalizing content.
    pub fn push_italic_safe(mut self, content: &str) -> Self {
        self.0.push('_');
        self.0.push_str(&normalize(content).replace('_', "＿"));
        self.0.push('_');

        self
    }

    /// Pushes an inline bold text to your message normalizing content.
    pub fn push_bold_safe(mut self, content: &str) -> Self {
        self.0.push_str("**");
        self.0.push_str(&normalize(content).replace("**", "∗∗"));
        self.0.push_str("**");

        self
    }

    /// Pushes an underlined inline text to your message normalizing content.
    pub fn push_underline_safe(mut self, content: &str) -> Self {
        self.0.push_str("__");
        self.0.push_str(&normalize(content).replace("__", "＿＿"));
        self.0.push_str("__");

        self
    }

    /// Pushes a strikethrough inline text to your message normalizing content.
    pub fn push_strike_safe(mut self, content: &str) -> Self {
        self.0.push_str("~~");
        self.0.push_str(&normalize(content).replace("~~", "∼∼"));
        self.0.push_str("~~");

        self
    }

    /// Mentions the [`Role`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`RoleId`]. Refer to
    /// `RoleId`'s documentation for more information.
    ///
    /// Refer to `RoleId`'s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [`Role`]: ../model/struct.Role.html
    /// [`RoleId`]: ../model/struct.RoleId.html
    /// [Display implementation]: ../model/struct.RoleId.html#method.fmt-1
    pub fn role<R: Into<RoleId>>(mut self, role: R) -> Self {
        let _ = write!(self.0, "{}", role.into());

        self
    }

    /// Mentions the [`User`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`UserId`]. Refer to
    /// `UserId`'s documentation for more information.
    ///
    /// Refer to `UserId`'s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [`User`]: ../model/struct.User.html
    /// [`UserId`]: ../model/struct.UserId.html
    /// [Display implementation]: ../model/struct.UserId.html#method.fmt-1
    pub fn user<U: Into<UserId>>(mut self, user: U) -> Self {
        let _ = write!(self.0, "{}", user.into());

        self
    }
}

impl fmt::Display for MessageBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl Default for MessageBuilder {
    fn default() -> MessageBuilder {
        MessageBuilder(String::default())
    }
}
<commit_msg>Re-order message builder file<commit_after>use std::default::Default;
use std::fmt::{self, Write};
use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};

/// The Message Builder is an ergonomic utility to easily build a message,
/// by adding text and mentioning mentionable structs.
///
/// The finalized value can be accessed via [`build`] or the inner value.
///
/// # Examples
///
/// Build a message, mentioning a [`user`] and an [`emoji`], and retrieving the
/// value:
///
/// ```rust,ignore
/// use serenity::utils::MessageBuilder;
///
/// // assuming an `emoji` and `user` have already been bound
///
/// let content = MessageBuilder::new()
///     .push("You sent a message, ")
///     .mention(user)
///     .push("! ")
///     .mention(emoji)
///     .build();
/// ```
///
/// [`build`]: #method.build
/// [`emoji`]: #method.emoji
/// [`user`]: #method.user
pub struct MessageBuilder(pub String);

impl MessageBuilder {
    /// Creates a new, empty-content builder.
    pub fn new() -> MessageBuilder {
        MessageBuilder::default()
    }

    /// Pulls the inner value out of the builder.
    ///
    /// # Examples
    ///
    /// This is equivilant to simply retrieving the tuple struct's first value:
    ///
    /// ```rust
    /// use serenity::utils::MessageBuilder;
    ///
    /// let content = MessageBuilder::new().push("test").0;
    ///
    /// assert_eq!(content, "test");
    /// ```
    pub fn build(self) -> String {
        self.0
    }

    /// Mentions the [`GuildChannel`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`ChannelId`]. Refer to
    /// `ChannelId`'s documentation for more information.
    ///
    /// Refer to `ChannelId`'s [Display implementation] for more information on
    /// how this is formatted.
    ///
    /// [`ChannelId`]: ../model/struct.ChannelId.html
    /// [`GuildChannel`]: ../model/struct.GuildChannel.html
    /// [Display implementation]: ../model/struct.ChannelId.html#method.fmt-1
    pub fn channel<C: Into<ChannelId>>(mut self, channel: C) -> Self {
        let _ = write!(self.0, "{}", channel.into());

        self
    }

    /// Displays the given emoji in the built message.
    ///
    /// Refer to `Emoji`s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [Display implementation]: ../model/struct.Emoji.html#method.fmt
    pub fn emoji(mut self, emoji: Emoji) -> Self {
        let _ = write!(self.0, "{}", emoji);

        self
    }

    /// Mentions something that implements the [`Mentionable`] trait.
    ///
    /// [`Mentionable`]: ../model/trait.Mentionable.html
    pub fn mention<M: Mentionable>(mut self, item: M) -> Self {
        let _ = write!(self.0, "{}", item.mention());

        self
    }

    /// Pushes a string to the internal message content.
    ///
    /// Note that this does not mutate either the given data or the internal
    /// message content in anyway prior to appending the given content to the
    /// internal message.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::MessageBuilder;
    ///
    /// let message = MessageBuilder::new().push("test");
    ///
    /// assert_eq!(message.push("ing").0, "testing");
    /// ```
    pub fn push(mut self, content: &str) -> Self {
        self.0.push_str(content);

        self
    }

    /// Pushes a code-block to your message, with optional syntax highlighting.
    pub fn push_codeblock(mut self, content: &str, language: Option<&str>) -> Self {
        self.0.push_str("```");

        if let Some(language) = language {
            self.0.push_str(language);
        }

        self.0.push('\n');
        self.0.push_str(content);
        self.0.push_str("\n```");

        self
    }

    /// Pushes an inline monospaced text to your message.
    pub fn push_mono(mut self, content: &str) -> Self {
        self.0.push('`');
        self.0.push_str(content);
        self.0.push('`');

        self
    }

    /// Pushes an inline italicized text to your message.
    pub fn push_italic(mut self, content: &str) -> Self {
        self.0.push('_');
        self.0.push_str(content);
        self.0.push('_');

        self
    }

    /// Pushes an inline bold text to your message.
    pub fn push_bold(mut self, content: &str) -> Self {
        self.0.push_str("**");
        self.0.push_str(content);
        self.0.push_str("**");

        self
    }

    /// Pushes an underlined inline text to your message.
    pub fn push_underline(mut self, content: &str) -> Self {
        self.0.push_str("__");
        self.0.push_str(content);
        self.0.push_str("__");

        self
    }

    /// Pushes a strikethrough inline text to your message.
    pub fn push_strike(mut self, content: &str) -> Self {
        self.0.push_str("~~");
        self.0.push_str(content);
        self.0.push_str("~~");

        self
    }

    /// Pushes text to your message, but normalizing content - that means
    /// ensuring that there's no unwanted formatting, mention spam etc.
    pub fn push_safe(mut self, content: &str) -> Self {
        let normalized = normalize(content)
            .replace('*', "\\*")
            .replace('`', "\\`")
            .replace('_', "\\_");

        self.0.push_str(&normalized);

        self
    }

    /// Pushes a code-block to your message normalizing content.
    pub fn push_codeblock_safe(mut self, content: &str, language: Option<&str>)
        -> Self {
        let content = &normalize(content)
            .replace("```", "\u{201B}\u{201B}\u{201B}");

        self.0.push_str("```");

        if let Some(language) = language {
            self.0.push_str(language);
        }

        self.0.push('\n');
        self.0.push_str(content);
        self.0.push_str("```");

        self
    }

    /// Pushes an inline monospaced text to your message normalizing content.
    pub fn push_mono_safe(mut self, content: &str) -> Self {
        self.0.push('`');
        self.0.push_str(&normalize(content).replace("`", "\u{201B}"));
        self.0.push('`');

        self
    }

    /// Pushes an inline italicized text to your message normalizing content.
    pub fn push_italic_safe(mut self, content: &str) -> Self {
        self.0.push('_');
        self.0.push_str(&normalize(content).replace('_', "＿"));
        self.0.push('_');

        self
    }

    /// Pushes an inline bold text to your message normalizing content.
    pub fn push_bold_safe(mut self, content: &str) -> Self {
        self.0.push_str("**");
        self.0.push_str(&normalize(content).replace("**", "∗∗"));
        self.0.push_str("**");

        self
    }

    /// Pushes an underlined inline text to your message normalizing content.
    pub fn push_underline_safe(mut self, content: &str) -> Self {
        self.0.push_str("__");
        self.0.push_str(&normalize(content).replace("__", "＿＿"));
        self.0.push_str("__");

        self
    }

    /// Pushes a strikethrough inline text to your message normalizing content.
    pub fn push_strike_safe(mut self, content: &str) -> Self {
        self.0.push_str("~~");
        self.0.push_str(&normalize(content).replace("~~", "∼∼"));
        self.0.push_str("~~");

        self
    }

    /// Mentions the [`Role`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`RoleId`]. Refer to
    /// `RoleId`'s documentation for more information.
    ///
    /// Refer to `RoleId`'s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [`Role`]: ../model/struct.Role.html
    /// [`RoleId`]: ../model/struct.RoleId.html
    /// [Display implementation]: ../model/struct.RoleId.html#method.fmt-1
    pub fn role<R: Into<RoleId>>(mut self, role: R) -> Self {
        let _ = write!(self.0, "{}", role.into());

        self
    }

    /// Mentions the [`User`] in the built message.
    ///
    /// This accepts anything that converts _into_ a [`UserId`]. Refer to
    /// `UserId`'s documentation for more information.
    ///
    /// Refer to `UserId`'s [Display implementation] for more information on how
    /// this is formatted.
    ///
    /// [`User`]: ../model/struct.User.html
    /// [`UserId`]: ../model/struct.UserId.html
    /// [Display implementation]: ../model/struct.UserId.html#method.fmt-1
    pub fn user<U: Into<UserId>>(mut self, user: U) -> Self {
        let _ = write!(self.0, "{}", user.into());

        self
    }
}

impl fmt::Display for MessageBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl Default for MessageBuilder {
    fn default() -> MessageBuilder {
        MessageBuilder(String::default())
    }
}

fn normalize(text: &str) -> String {
    // Remove everyone and here mentions
    // This changes 'at' symbol to a full-width variation
    text.replace("@everyone", "＠everyone")
        .replace("@here", "＠here")
        // Remove invite links and popular scam websites, mostly to prevent the
        // current user from triggering various ad detectors
        .replace("discord.gg", "discord․gg")
        .replace("discord.me", "discord․me")
        .replace("discordlist.net", "discordlist․net")
        .replace("discordservers.com", "discordservers․com")
        .replace("discordapp.com/invite", "discordapp․com/invite")
        // Remove right-to-left and other similar overrides
        .replace('\u{202E}', " ") // RTL
        .replace('\u{200F}', " ") // RTL Mark
        .replace('\u{202B}', " ") // RTL Embedding
        .replace('\u{200B}', " ") // Zero-width space
        .replace('\u{200D}', " ") // Zero-width joiner
        .replace('\u{200C}', " ") // Zero-width non-joiner
}
<|endoftext|>


<commit_before>// -*- rust-indent-offset: 2 -*-
// More compact, just for slides.

use std::iter::Iterator;

/// Convenient type synonym for a common pattern of usage.
/// More generally, Vec could be replaced by a Semigroup (Add).
pub type Validation<T, E> = Result<T, Vec<E>>;

#[inline]
pub fn single<T, E>(result: Result<T, E>) -> Validation<T, E> {
  result.map_err(|e| vec![e])
}

/// Combine successful results with `f`, but accumulate errors.
/// Important: any error causes the whole result to be an error!
pub fn add_with<V, T, U, E, F>(result1: Validation<V, E>,
                            result2: Validation<T, E>,
                            mut f: F) -> Validation<U, E>
  where F: FnMut(V, T) -> U
{
  match (result1, result2) {
    (Ok(v),       Ok(t))   => Ok(f(v, t)),
    (Ok(_),       Err(e2)) => Err(e2),
    (Err(e1),     Ok(_))   => Err(e1),
    (Err(mut e1), Err(e2)) => Err({ e1.extend(e2.into_iter()); e1 })
  }
}

/// Combine a stream of Result to a Validation, accumulating successes.
pub fn combine_results<T,
                       E,
                       I>(iter: I)
  -> Validation<Vec<T>, E> where
  I: Iterator<Item = Result<T, E>>
{
  iter.map(single)
      .fold(Ok(vec![]),
            |v, t|
            add_with(v, t,
                     |mut x, y| {
                       x.push(y);
                       x
                     }))
}
<commit_msg>Remove unnecessary mut.<commit_after>// -*- rust-indent-offset: 2 -*-
// More compact, just for slides.

use std::iter::Iterator;

/// Convenient type synonym for a common pattern of usage.
/// More generally, Vec could be replaced by a Semigroup (Add).
pub type Validation<T, E> = Result<T, Vec<E>>;

#[inline]
pub fn single<T, E>(result: Result<T, E>) -> Validation<T, E> {
  result.map_err(|e| vec![e])
}

/// Combine successful results with `f`, but accumulate errors.
/// Important: any error causes the whole result to be an error!
pub fn add_with<V, T, U, E, F>(result1: Validation<V, E>,
                            result2: Validation<T, E>,
                            f: F) -> Validation<U, E>
  where F: Fn(V, T) -> U
{
  match (result1, result2) {
    (Ok(v),       Ok(t))   => Ok(f(v, t)),
    (Ok(_),       Err(e2)) => Err(e2),
    (Err(e1),     Ok(_))   => Err(e1),
    (Err(mut e1), Err(e2)) => Err({ e1.extend(e2.into_iter()); e1 })
  }
}

/// Combine a stream of Result to a Validation, accumulating successes.
pub fn combine_results<T,
                       E,
                       I>(iter: I)
  -> Validation<Vec<T>, E> where
  I: Iterator<Item = Result<T, E>>
{
  iter.map(single)
      .fold(Ok(vec![]),
            |v, t|
            add_with(v, t,
                     |mut x, y| {
                       x.push(y);
                       x
                     }))
}
<|endoftext|>


<commit_before>#[macro_use] extern crate wlroots;

use std::ptr::null_mut;
use std::env;
use std::time::Instant;
use std::os::raw::{c_void, c_int};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;

fn main() {
    if env::var("DISPLAY").is_ok() {
        panic!("Detected that X is running. Run this in its own virtual terminal.")
    } else if env::var("WAYLAND_DISPLAY").is_ok() {
        panic!("Detected that Wayland is running. Run this in its own virtual terminal")
    }
    let empty = ();
    {
        // NOTE that because we pass `done` to a timeout callback,
        // it must be declared before session to ensure they are dropped
        // in the correct order.
        // Try reordering `done` to after `session` and see the error.
        let done = AtomicBool::new(false);
        let mut session = wlroots::Session::new()
            .expect("Could not start session");
        // init output
        wlroots::output::init(&mut session);
        // set loop to break after 20 seconds.
        session.set_timeout(&done,
                            |done: &AtomicBool| {
                                done.store(true, Ordering::Relaxed)
                            },
                            20000);
        // Set the outputs to turn off at 5 seconds
        session.set_timeout(&empty,
                            disable_outputs,
                            5000);
        // Set the outputs to turn on at 5 seconds
        session.set_timeout(&empty,
                            enable_outputs,
                            10000);
        // Finish initializing the backend
        session.backend.init().expect("Backend could not initalize");
        // Now that the outputs are registered add a callback per frame.
        unsafe {
            add_frame_callbacks();
        }
        while ! done.load(Ordering::Relaxed) {
            match session.dispatch_event_loop() {
                0 => {}
                err_code => {
                    println!("Error: {:?}", err_code);
                    break;
                }
            }
        }
        // TODO Ensure that this all cleaned up properly in RAII
    }

}

fn disable_outputs(_: &()) {
    let mut outputs = wlroots::output::OUTPUTS.try_lock()
        .expect("Output lock was already acquired");
    for mut output in &mut *outputs {
        output.disable()
    }
}

fn enable_outputs(_: &()) {
    let mut outputs = wlroots::output::OUTPUTS.try_lock()
    .expect("Output lock was already acquired");
    for mut output in &mut *outputs {
        output.enable()
    }
}

/*
NOTE: This is the only unsafe part of the program.

This draws directly to the screen, but the majority of the unsafe part is
unexposed machinery. We don't wrap this well, because in a real program
we will probably not need to do this.
*/
extern crate wayland_sys;
use wlroots::utils::wl_listener;
use wayland_sys::server;

// For graphical functions
mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
struct State {
    /// The color on the screen.
    color: [f32; 3],
    dec: i32,
    /// How long since the last frame was rendered.
    last_frame: Instant
}

impl State {
    unsafe fn new() -> Self {
        State {
            color: [1.0, 0.0, 0.0],
            dec: 0,
            last_frame: Instant::now()
        }
    }
}

// This is so wl_container_of works.
// repr(C) means the struct packing in deterministic.

#[repr(C)]
struct OutputWrapper {
    state: *mut State,
    output: wl_listener
}

unsafe fn add_frame_callbacks() {
    // We store the wl_listener in a struct, and grab it again
    // using the magic of wl_container_of.
    let mut output_frame_listener =wl_listener::new(draw_frame);
    // Keep a raw pointer to make sure wl_container_of works.
    //let mut output_raw = Box::into_raw(output_frame_listener);
    let mut state = Box::new(State::new());
    let mut state_raw = Box::into_raw(state);
    let mut output_wrapper = Box::new(OutputWrapper {
        state: state_raw,
        output: output_frame_listener as _
    });
    let outputs = wlroots::output::OUTPUTS.try_lock()
        .expect("Output lock was already acquired");
    for output in &*outputs {
        wlroots::utils::wl_signal_add(&mut (*output.inner).events.frame,
                                      &mut output_wrapper.output as &mut _);
    }
    ::std::mem::forget(output_wrapper);
}

unsafe extern "C" fn draw_frame(listener: *mut server::wl_listener,
                                data: *mut c_void) {
    // SUPER unsafe
    let output_wrapper = wl_container_of!(listener,
                                          OutputWrapper,
                                          output) as *mut OutputWrapper;
    let state = &mut *(*output_wrapper).state;
    let now = Instant::now();
    let delta = now.duration_since(state.last_frame);
    let seconds_delta= delta.as_secs();
    let nano_delta = delta.subsec_nanos() as u64;
    let ms = (seconds_delta * 1000) + nano_delta / 1000000;
    let inc = (state.dec + 1) % 3;
    state.color[inc as usize] += ms as f32 / 2000.0;
    state.color[state.dec as usize] -= ms as f32 / 2000.0;

    if state.color[state.dec as usize] < 0.0 {
        state.color[inc as usize] = 1.0;
        state.color[state.dec as usize] = 0.0;
        state.dec = inc;
    }
    state.last_frame = now;
    gl::ClearColor(state.color[0], state.color[1], state.color[2], 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

}
<commit_msg>Clarify why we don't wrap add_frame_callbacks<commit_after>#[macro_use] extern crate wlroots;

use std::ptr::null_mut;
use std::env;
use std::time::Instant;
use std::os::raw::{c_void, c_int};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;

fn main() {
    if env::var("DISPLAY").is_ok() {
        panic!("Detected that X is running. Run this in its own virtual terminal.")
    } else if env::var("WAYLAND_DISPLAY").is_ok() {
        panic!("Detected that Wayland is running. Run this in its own virtual terminal")
    }
    let empty = ();
    {
        // NOTE that because we pass `done` to a timeout callback,
        // it must be declared before session to ensure they are dropped
        // in the correct order.
        // Try reordering `done` to after `session` and see the error.
        let done = AtomicBool::new(false);
        let mut session = wlroots::Session::new()
            .expect("Could not start session");
        // init output
        wlroots::output::init(&mut session);
        // set loop to break after 20 seconds.
        session.set_timeout(&done,
                            |done: &AtomicBool| {
                                done.store(true, Ordering::Relaxed)
                            },
                            20000);
        // Set the outputs to turn off at 5 seconds
        session.set_timeout(&empty,
                            disable_outputs,
                            5000);
        // Set the outputs to turn on at 5 seconds
        session.set_timeout(&empty,
                            enable_outputs,
                            10000);
        // Finish initializing the backend
        session.backend.init().expect("Backend could not initalize");
        // Now that the outputs are registered add a callback per frame.
        // We don't wrap this because it's largely unnecessarily
        unsafe {
            add_frame_callbacks();
        }
        while ! done.load(Ordering::Relaxed) {
            match session.dispatch_event_loop() {
                0 => {}
                err_code => {
                    println!("Error: {:?}", err_code);
                    break;
                }
            }
        }
        // TODO Ensure that this all cleaned up properly in RAII
    }

}

fn disable_outputs(_: &()) {
    let mut outputs = wlroots::output::OUTPUTS.try_lock()
        .expect("Output lock was already acquired");
    for mut output in &mut *outputs {
        output.disable()
    }
}

fn enable_outputs(_: &()) {
    let mut outputs = wlroots::output::OUTPUTS.try_lock()
    .expect("Output lock was already acquired");
    for mut output in &mut *outputs {
        output.enable()
    }
}

/*
NOTE: This is the only unsafe part of the program.

This draws directly to the screen, but the majority of the unsafe part is
unexposed machinery. We don't wrap this well, because in a real program
we will probably not need to do this.
*/
extern crate wayland_sys;
use wlroots::utils::wl_listener;
use wayland_sys::server;

// For graphical functions
mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
struct State {
    /// The color on the screen.
    color: [f32; 3],
    dec: i32,
    /// How long since the last frame was rendered.
    last_frame: Instant
}

impl State {
    unsafe fn new() -> Self {
        State {
            color: [1.0, 0.0, 0.0],
            dec: 0,
            last_frame: Instant::now()
        }
    }
}

// This is so wl_container_of works.
// repr(C) means the struct packing in deterministic.

#[repr(C)]
struct OutputWrapper {
    state: *mut State,
    output: wl_listener
}

unsafe fn add_frame_callbacks() {
    // We store the wl_listener in a struct, and grab it again
    // using the magic of wl_container_of.
    let mut output_frame_listener =wl_listener::new(draw_frame);
    // Keep a raw pointer to make sure wl_container_of works.
    //let mut output_raw = Box::into_raw(output_frame_listener);
    let mut state = Box::new(State::new());
    let mut state_raw = Box::into_raw(state);
    let mut output_wrapper = Box::new(OutputWrapper {
        state: state_raw,
        output: output_frame_listener as _
    });
    let outputs = wlroots::output::OUTPUTS.try_lock()
        .expect("Output lock was already acquired");
    for output in &*outputs {
        wlroots::utils::wl_signal_add(&mut (*output.inner).events.frame,
                                      &mut output_wrapper.output as &mut _);
    }
    ::std::mem::forget(output_wrapper);
}

unsafe extern "C" fn draw_frame(listener: *mut server::wl_listener,
                                data: *mut c_void) {
    // SUPER unsafe
    let output_wrapper = wl_container_of!(listener,
                                          OutputWrapper,
                                          output) as *mut OutputWrapper;
    let state = &mut *(*output_wrapper).state;
    let now = Instant::now();
    let delta = now.duration_since(state.last_frame);
    let seconds_delta= delta.as_secs();
    let nano_delta = delta.subsec_nanos() as u64;
    let ms = (seconds_delta * 1000) + nano_delta / 1000000;
    let inc = (state.dec + 1) % 3;
    state.color[inc as usize] += ms as f32 / 2000.0;
    state.color[state.dec as usize] -= ms as f32 / 2000.0;

    if state.color[state.dec as usize] < 0.0 {
        state.color[inc as usize] = 1.0;
        state.color[state.dec as usize] = 0.0;
        state.dec = inc;
    }
    state.last_frame = now;
    gl::ClearColor(state.color[0], state.color[1], state.color[2], 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

}
<|endoftext|>


<commit_before><commit_msg>Fix broken alignement between waveforms after range playback (#84)<commit_after><|endoftext|>