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

use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::PathBuf,
};

use itertools::{Either, Itertools};
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Item;

use autocxx_integration_tests::{CodeChecker, CodeCheckerFns, TestError};

/// Generates a closure which can be used to ensure that the given symbol
/// is mentioned in the output and has documentation attached.
/// The idea is that this is what we do in cases where we can't generate code properly.
pub(crate) fn make_error_finder(error_symbol: &'static str) -> CodeChecker {
    Box::new(ErrorFinder(error_symbol))
}
struct ErrorFinder(&'static str);

impl CodeCheckerFns for ErrorFinder {
    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
        let ffi_items = find_ffi_items(rs)?;
        // Ensure there's some kind of struct entry for this symbol
        let error_item = ffi_items
            .into_iter()
            .filter_map(|i| match i {
                Item::Struct(its) if its.ident == self.0 => Some(its),
                _ => None,
            })
            .next()
            .ok_or(TestError::RsCodeExaminationFail(
                "Couldn't find item".into(),
            ))?;
        // Ensure doc attribute
        error_item
            .attrs
            .into_iter()
            .find(|a| a.path.get_ident().filter(|p| *p == "doc").is_some())
            .ok_or(TestError::RsCodeExaminationFail("Item had no docs".into()))?;
        Ok(())
    }
}

fn find_ffi_items(f: syn::File) -> Result<Vec<Item>, TestError> {
    let md = f
        .items
        .into_iter()
        .filter_map(|i| match i {
            Item::Mod(itm) => Some(itm),
            _ => None,
        })
        .next()
        .ok_or(TestError::RsCodeExaminationFail("No mods in file".into()))?;
    let mut items = Vec::new();
    find_all_non_mod_items(md, &mut items);
    Ok(items)
}

fn find_all_non_mod_items(md: syn::ItemMod, items: &mut Vec<Item>) {
    let (more_mods, mut these_items): (Vec<_>, Vec<_>) = md
        .content
        .into_iter()
        .flat_map(|(_, more_items)| more_items.into_iter())
        .partition_map(|i| match i {
            Item::Mod(itm) => Either::Left(itm),
            _ => Either::Right(i),
        });
    items.append(&mut these_items);
    for md in more_mods.into_iter() {
        find_all_non_mod_items(md, items);
    }
}

struct StringFinder(Vec<&'static str>);

impl CodeCheckerFns for StringFinder {
    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
        let mut ts = TokenStream::new();
        rs.to_tokens(&mut ts);
        let toks = ts.to_string();
        for msg in &self.0 {
            if !toks.contains(msg) {
                return Err(TestError::RsCodeExaminationFail(
                    "Couldn't find string".into(),
                ));
            };
        }
        Ok(())
    }
}

/// Returns a code checker which simply hunts for a given string in the results
pub(crate) fn make_string_finder(error_texts: Vec<&'static str>) -> CodeChecker {
    Box::new(StringFinder(error_texts))
}

/// Counts the number of generated C++ files.
pub(crate) struct CppCounter {
    cpp_count: usize,
}

impl CppCounter {
    pub(crate) fn new(cpp_count: usize) -> Self {
        Self { cpp_count }
    }
}

impl CodeCheckerFns for CppCounter {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        if cpp.len() == self.cpp_count {
            Ok(())
        } else {
            Err(TestError::CppCodeExaminationFail)
        }
    }

    fn skip_build(&self) -> bool {
        true
    }
}

/// Searches generated C++ for strings we want to find, or want _not_ to find,
/// or both.
pub(crate) struct CppMatcher<'a> {
    positive_matches: &'a [&'a str],
    negative_matches: &'a [&'a str],
}

impl<'a> CppMatcher<'a> {
    pub(crate) fn new(positive_matches: &'a [&'a str], negative_matches: &'a [&'a str]) -> Self {
        Self {
            positive_matches,
            negative_matches,
        }
    }
}

impl<'a> CodeCheckerFns for CppMatcher<'a> {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        let mut positives_needed = self.positive_matches.to_vec();
        for filename in cpp {
            let file = File::open(filename).unwrap();
            let lines = BufReader::new(file).lines();
            for l in lines.filter_map(|l| l.ok()) {
                if self.negative_matches.iter().any(|neg| l.contains(neg)) {
                    return Err(TestError::CppCodeExaminationFail);
                }
                positives_needed.retain(|pos| !l.contains(pos));
            }
        }
        if positives_needed.is_empty() {
            Ok(())
        } else {
            Err(TestError::CppCodeExaminationFail)
        }
    }
}

pub(crate) struct NoSystemHeadersChecker;

impl CodeCheckerFns for NoSystemHeadersChecker {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        for filename in cpp {
            let file = File::open(filename).unwrap();
            if BufReader::new(file)
                .lines()
                .any(|l| l.as_ref().unwrap().starts_with("#include <"))
            {
                return Err(TestError::CppCodeExaminationFail);
            }
        }
        Ok(())
    }
    fn skip_build(&self) -> bool {
        true
    }
}
<commit_msg>Clippy fix.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::PathBuf,
};

use itertools::{Either, Itertools};
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Item;

use autocxx_integration_tests::{CodeChecker, CodeCheckerFns, TestError};

/// Generates a closure which can be used to ensure that the given symbol
/// is mentioned in the output and has documentation attached.
/// The idea is that this is what we do in cases where we can't generate code properly.
pub(crate) fn make_error_finder(error_symbol: &'static str) -> CodeChecker {
    Box::new(ErrorFinder(error_symbol))
}
struct ErrorFinder(&'static str);

impl CodeCheckerFns for ErrorFinder {
    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
        let ffi_items = find_ffi_items(rs)?;
        // Ensure there's some kind of struct entry for this symbol
        let error_item = ffi_items
            .into_iter()
            .filter_map(|i| match i {
                Item::Struct(its) if its.ident == self.0 => Some(its),
                _ => None,
            })
            .next()
            .ok_or_else(|| TestError::RsCodeExaminationFail("Couldn't find item".into()))?;
        // Ensure doc attribute
        error_item
            .attrs
            .into_iter()
            .find(|a| a.path.get_ident().filter(|p| *p == "doc").is_some())
            .ok_or_else(|| TestError::RsCodeExaminationFail("Item had no docs".into()))?;
        Ok(())
    }
}

fn find_ffi_items(f: syn::File) -> Result<Vec<Item>, TestError> {
    let md = f
        .items
        .into_iter()
        .filter_map(|i| match i {
            Item::Mod(itm) => Some(itm),
            _ => None,
        })
        .next()
        .ok_or_else(|| TestError::RsCodeExaminationFail("No mods in file".into()))?;
    let mut items = Vec::new();
    find_all_non_mod_items(md, &mut items);
    Ok(items)
}

fn find_all_non_mod_items(md: syn::ItemMod, items: &mut Vec<Item>) {
    let (more_mods, mut these_items): (Vec<_>, Vec<_>) = md
        .content
        .into_iter()
        .flat_map(|(_, more_items)| more_items.into_iter())
        .partition_map(|i| match i {
            Item::Mod(itm) => Either::Left(itm),
            _ => Either::Right(i),
        });
    items.append(&mut these_items);
    for md in more_mods.into_iter() {
        find_all_non_mod_items(md, items);
    }
}

struct StringFinder(Vec<&'static str>);

impl CodeCheckerFns for StringFinder {
    fn check_rust(&self, rs: syn::File) -> Result<(), TestError> {
        let mut ts = TokenStream::new();
        rs.to_tokens(&mut ts);
        let toks = ts.to_string();
        for msg in &self.0 {
            if !toks.contains(msg) {
                return Err(TestError::RsCodeExaminationFail(
                    "Couldn't find string".into(),
                ));
            };
        }
        Ok(())
    }
}

/// Returns a code checker which simply hunts for a given string in the results
pub(crate) fn make_string_finder(error_texts: Vec<&'static str>) -> CodeChecker {
    Box::new(StringFinder(error_texts))
}

/// Counts the number of generated C++ files.
pub(crate) struct CppCounter {
    cpp_count: usize,
}

impl CppCounter {
    pub(crate) fn new(cpp_count: usize) -> Self {
        Self { cpp_count }
    }
}

impl CodeCheckerFns for CppCounter {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        if cpp.len() == self.cpp_count {
            Ok(())
        } else {
            Err(TestError::CppCodeExaminationFail)
        }
    }

    fn skip_build(&self) -> bool {
        true
    }
}

/// Searches generated C++ for strings we want to find, or want _not_ to find,
/// or both.
pub(crate) struct CppMatcher<'a> {
    positive_matches: &'a [&'a str],
    negative_matches: &'a [&'a str],
}

impl<'a> CppMatcher<'a> {
    pub(crate) fn new(positive_matches: &'a [&'a str], negative_matches: &'a [&'a str]) -> Self {
        Self {
            positive_matches,
            negative_matches,
        }
    }
}

impl<'a> CodeCheckerFns for CppMatcher<'a> {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        let mut positives_needed = self.positive_matches.to_vec();
        for filename in cpp {
            let file = File::open(filename).unwrap();
            let lines = BufReader::new(file).lines();
            for l in lines.filter_map(|l| l.ok()) {
                if self.negative_matches.iter().any(|neg| l.contains(neg)) {
                    return Err(TestError::CppCodeExaminationFail);
                }
                positives_needed.retain(|pos| !l.contains(pos));
            }
        }
        if positives_needed.is_empty() {
            Ok(())
        } else {
            Err(TestError::CppCodeExaminationFail)
        }
    }
}

pub(crate) struct NoSystemHeadersChecker;

impl CodeCheckerFns for NoSystemHeadersChecker {
    fn check_cpp(&self, cpp: &[PathBuf]) -> Result<(), TestError> {
        for filename in cpp {
            let file = File::open(filename).unwrap();
            if BufReader::new(file)
                .lines()
                .any(|l| l.as_ref().unwrap().starts_with("#include <"))
            {
                return Err(TestError::CppCodeExaminationFail);
            }
        }
        Ok(())
    }
    fn skip_build(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use humantime::parse_duration;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::time::Duration;
use structopt::clap::arg_enum;
use structopt::StructOpt;
use thiserror::Error;

use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::io::gpio::GpioPin;
use crate::io::spi::SpiParams;
use crate::io::uart::UartParams;
use crate::transport::Capability;

mod eeprom;
mod legacy;
mod primitive;
mod rescue;

pub use legacy::LegacyBootstrapError;
pub use rescue::RescueError;

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum BootstrapError {
    #[error("Invalid hash length: {0}")]
    InvalidHashLength(usize),
}
impl_serializable_error!(BootstrapError);

arg_enum! {
    /// `BootstrapProtocol` describes the supported types of bootstrap.
    /// The `Primitive` SPI protocol is used by OpenTitan during development.
    /// The `Legacy` SPI protocol is used by previous generations of Google Titan-class chips.
    /// The `Eeprom` SPI protocol is planned to be implemented for OpenTitan.
    /// The `Rescue` UART protocol is used by Google Ti50 firmware.
    /// The 'Emulator' value indicates that this tool has a direct way
    /// of communicating with the OpenTitan emulator, to replace the
    /// contents of the emulated flash storage.
    #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
    pub enum BootstrapProtocol {
        Primitive,
        Legacy,
        Eeprom,
        Rescue,
        Emulator,
    }
}

// Implementations of bootstrap need to implement the `UpdateProtocol` trait.
trait UpdateProtocol {
    /// Called before any action is taken, to allow the protocol to verify that the transport
    /// supports SPI/UART or whatever it needs.
    fn verify_capabilities(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
    ) -> Result<()>;
    /// Indicates whether the caller should assert the bootstrap pin and reset the chip, before
    /// invoking update().
    fn uses_common_bootstrap_reset(&self) -> bool;
    /// Invoked to perform the actual transfer of an executable image to the OpenTitan chip.
    fn update(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
        payload: &[u8],
    ) -> Result<()>;
}

/// Options which control bootstrap behavior.
/// The meaning of each of these values depends on the specific bootstrap protocol being used.
#[derive(Clone, Debug, StructOpt, Serialize, Deserialize)]
pub struct BootstrapOptions {
    #[structopt(flatten)]
    pub uart_params: UartParams,
    #[structopt(flatten)]
    pub spi_params: SpiParams,
    #[structopt(
        short,
        long,
        possible_values = &BootstrapProtocol::variants(),
        case_insensitive = true,
        default_value = "primitive",
        help = "Bootstrap protocol to use"
    )]
    pub protocol: BootstrapProtocol,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the reset delay")]
    pub reset_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the inter-frame delay")]
    pub inter_frame_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the flash-erase delay")]
    pub flash_erase_delay: Option<Duration>,
}

/// Bootstrap wraps and drives the various bootstrap protocols.
pub struct Bootstrap<'a> {
    pub protocol: BootstrapProtocol,
    pub uart_params: &'a UartParams,
    pub spi_params: &'a SpiParams,
    reset_pin: Rc<dyn GpioPin>,
    bootstrap_pin: Rc<dyn GpioPin>,
    reset_delay: Duration,
}

impl<'a> Bootstrap<'a> {
    const RESET_DELAY: Duration = Duration::from_millis(200);

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.
    pub fn update(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
    ) -> Result<()> {
        if transport
            .capabilities()?
            .request(Capability::PROXY)
            .ok()
            .is_ok()
        {
            // The transport happens to be connection to a remove opentitan session.  Pass
            // payload along with all relevant command line arguments to the remote session, and
            // it will run the actual bootstrapping logic.
            transport.proxy_ops()?.bootstrap(options, payload)?;
            return Ok(());
        }
        let updater: Box<dyn UpdateProtocol> = match options.protocol {
            BootstrapProtocol::Primitive => Box::new(primitive::Primitive::new(&options)),
            BootstrapProtocol::Legacy => Box::new(legacy::Legacy::new(&options)),
            BootstrapProtocol::Rescue => Box::new(rescue::Rescue::new(&options)),
            BootstrapProtocol::Eeprom => Box::new(eeprom::Eeprom::new()),
            BootstrapProtocol::Emulator => {
                // Not intended to be implemented by this struct.
                unimplemented!();
            }
        };
        Bootstrap {
            protocol: options.protocol,
            uart_params: &options.uart_params,
            spi_params: &options.spi_params,
            reset_pin: transport.gpio_pin("RESET")?,
            bootstrap_pin: transport.gpio_pin("BOOTSTRAP")?,
            reset_delay: options.reset_delay.unwrap_or(Self::RESET_DELAY),
        }
        .do_update(updater, transport, payload)
    }

    fn do_update(
        &self,
        updater: Box<dyn UpdateProtocol>,
        transport: &TransportWrapper,
        payload: &[u8],
    ) -> Result<()> {
        updater.verify_capabilities(&self, transport)?;
        let perform_bootstrap_reset = updater.uses_common_bootstrap_reset();

        if perform_bootstrap_reset {
            log::info!("Asserting bootstrap pins...");
            self.bootstrap_pin.write(true)?;

            log::info!("Reseting the target...");
            self.reset_pin.write(false)?; // Low active
            std::thread::sleep(self.reset_delay);
            self.reset_pin.write(true)?; // Release reset
            std::thread::sleep(self.reset_delay);

            log::info!("Performing bootstrap...");
        }
        let result = updater.update(&self, transport, payload);

        if perform_bootstrap_reset {
            log::info!("Releasing bootstrap pins...");
            self.bootstrap_pin.write(false)?;
        }
        result
    }
}
<commit_msg>[opentitanlib] Use new strap pins in Bootstrap::do_update()<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use humantime::parse_duration;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::time::Duration;
use structopt::clap::arg_enum;
use structopt::StructOpt;
use thiserror::Error;

use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::io::gpio::GpioPin;
use crate::io::spi::SpiParams;
use crate::io::uart::UartParams;
use crate::transport::Capability;

mod eeprom;
mod legacy;
mod primitive;
mod rescue;

pub use legacy::LegacyBootstrapError;
pub use rescue::RescueError;

#[derive(Debug, Error, Serialize, Deserialize)]
pub enum BootstrapError {
    #[error("Invalid hash length: {0}")]
    InvalidHashLength(usize),
}
impl_serializable_error!(BootstrapError);

arg_enum! {
    /// `BootstrapProtocol` describes the supported types of bootstrap.
    /// The `Primitive` SPI protocol is used by OpenTitan during development.
    /// The `Legacy` SPI protocol is used by previous generations of Google Titan-class chips.
    /// The `Eeprom` SPI protocol is planned to be implemented for OpenTitan.
    /// The `Rescue` UART protocol is used by Google Ti50 firmware.
    /// The 'Emulator' value indicates that this tool has a direct way
    /// of communicating with the OpenTitan emulator, to replace the
    /// contents of the emulated flash storage.
    #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
    pub enum BootstrapProtocol {
        Primitive,
        Legacy,
        Eeprom,
        Rescue,
        Emulator,
    }
}

// Implementations of bootstrap need to implement the `UpdateProtocol` trait.
trait UpdateProtocol {
    /// Called before any action is taken, to allow the protocol to verify that the transport
    /// supports SPI/UART or whatever it needs.
    fn verify_capabilities(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
    ) -> Result<()>;
    /// Indicates whether the caller should assert the bootstrap pin and reset the chip, before
    /// invoking update().
    fn uses_common_bootstrap_reset(&self) -> bool;
    /// Invoked to perform the actual transfer of an executable image to the OpenTitan chip.
    fn update(
        &self,
        container: &Bootstrap,
        transport: &TransportWrapper,
        payload: &[u8],
    ) -> Result<()>;
}

/// Options which control bootstrap behavior.
/// The meaning of each of these values depends on the specific bootstrap protocol being used.
#[derive(Clone, Debug, StructOpt, Serialize, Deserialize)]
pub struct BootstrapOptions {
    #[structopt(flatten)]
    pub uart_params: UartParams,
    #[structopt(flatten)]
    pub spi_params: SpiParams,
    #[structopt(
        short,
        long,
        possible_values = &BootstrapProtocol::variants(),
        case_insensitive = true,
        default_value = "primitive",
        help = "Bootstrap protocol to use"
    )]
    pub protocol: BootstrapProtocol,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the reset delay")]
    pub reset_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the inter-frame delay")]
    pub inter_frame_delay: Option<Duration>,
    #[structopt(long, parse(try_from_str=parse_duration), help = "Duration of the flash-erase delay")]
    pub flash_erase_delay: Option<Duration>,
}

/// Bootstrap wraps and drives the various bootstrap protocols.
pub struct Bootstrap<'a> {
    pub protocol: BootstrapProtocol,
    pub uart_params: &'a UartParams,
    pub spi_params: &'a SpiParams,
    reset_pin: Rc<dyn GpioPin>,
    reset_delay: Duration,
}

impl<'a> Bootstrap<'a> {
    const RESET_DELAY: Duration = Duration::from_millis(200);

    /// Perform the update, sending the firmware `payload` to a SPI or UART target depending on
    /// given `options`, which specifies protocol and port to use.
    pub fn update(
        transport: &TransportWrapper,
        options: &BootstrapOptions,
        payload: &[u8],
    ) -> Result<()> {
        if transport
            .capabilities()?
            .request(Capability::PROXY)
            .ok()
            .is_ok()
        {
            // The transport happens to be connection to a remove opentitan session.  Pass
            // payload along with all relevant command line arguments to the remote session, and
            // it will run the actual bootstrapping logic.
            transport.proxy_ops()?.bootstrap(options, payload)?;
            return Ok(());
        }
        let updater: Box<dyn UpdateProtocol> = match options.protocol {
            BootstrapProtocol::Primitive => Box::new(primitive::Primitive::new(&options)),
            BootstrapProtocol::Legacy => Box::new(legacy::Legacy::new(&options)),
            BootstrapProtocol::Rescue => Box::new(rescue::Rescue::new(&options)),
            BootstrapProtocol::Eeprom => Box::new(eeprom::Eeprom::new()),
            BootstrapProtocol::Emulator => {
                // Not intended to be implemented by this struct.
                unimplemented!();
            }
        };
        Bootstrap {
            protocol: options.protocol,
            uart_params: &options.uart_params,
            spi_params: &options.spi_params,
            reset_pin: transport.gpio_pin("RESET")?,
            reset_delay: options.reset_delay.unwrap_or(Self::RESET_DELAY),
        }
        .do_update(updater, transport, payload)
    }

    fn do_update(
        &self,
        updater: Box<dyn UpdateProtocol>,
        transport: &TransportWrapper,
        payload: &[u8],
    ) -> Result<()> {
        updater.verify_capabilities(&self, transport)?;
        let perform_bootstrap_reset = updater.uses_common_bootstrap_reset();

        if perform_bootstrap_reset {
            log::info!("Asserting bootstrap pins...");
            transport.apply_pin_strapping("ROM_BOOTSTRAP")?;

            log::info!("Reseting the target...");
            transport.apply_pin_strapping("RESET")?;
            std::thread::sleep(self.reset_delay);
            transport.remove_pin_strapping("RESET")?;
            std::thread::sleep(self.reset_delay);

            log::info!("Performing bootstrap...");
        }
        let result = updater.update(&self, transport, payload);

        if perform_bootstrap_reset {
            log::info!("Releasing bootstrap pins...");
            transport.remove_pin_strapping("ROM_BOOTSTRAP")?;
        }
        result
    }
}
<|endoftext|>


<commit_before>use ide_db::helpers::FamousDefs;
use syntax::{
    ast::{self, edit::AstNodeEdit, make, ArgListOwner},
    AstNode,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

/// Assist: convert_iter_for_each_to_for
//
/// Converts an Iterator::for_each function into a for loop.
///
/// ```rust
/// fn main() {
///     let vec = vec![(1, 2), (2, 3), (3, 4)];
///     x.iter().for_each(|(x, y)| {
///         println!("x: {}, y: {}", x, y);
///    })
/// }
/// ```
/// ->
/// ```rust
/// fn main() {
///     let vec = vec![(1, 2), (2, 3), (3, 4)];
///     for (x, y) in x.iter() {
///         println!("x: {}, y: {}", x, y);
///     });
/// }
/// ```
pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?;
    let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);

    let closure = match method.arg_list()?.args().next()? {
        ast::Expr::ClosureExpr(expr) => expr,
        _ => return None,
    };

    let (method, receiver) = validate_method_call_expr(&ctx.sema, method)?;

    let param_list = closure.param_list()?;
    let param = param_list.params().next()?.pat()?;
    let body = closure.body()?;

    let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());

    acc.add(
        AssistId("convert_iter_for_each_to_for", AssistKind::RefactorRewrite),
        "Replace this `Iterator::for_each` with a for loop",
        syntax.text_range(),
        |builder| {
            let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level());

            let block = match body {
                ast::Expr::BlockExpr(block) => block,
                _ => make::block_expr(Vec::new(), Some(body)),
            }
            .reset_indent()
            .indent(indent);

            let expr_for_loop = make::expr_for_loop(param, receiver, block);
            builder.replace(syntax.text_range(), expr_for_loop.syntax().text())
        },
    )
}

fn validate_method_call_expr(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    expr: ast::MethodCallExpr,
) -> Option<(ast::Expr, ast::Expr)> {
    if expr.name_ref()?.text() != "for_each" {
        return None;
    }

    let receiver = expr.receiver()?;
    let expr = ast::Expr::MethodCallExpr(expr);

    let it_type = sema.type_of_expr(&receiver)?;
    let module = sema.scope(receiver.syntax()).module()?;
    let krate = module.krate();

    let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
    it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, receiver))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    const EMPTY_ITER_FIXTURE: &'static str = r"
//- /lib.rs deps:core crate:empty_iter
pub struct EmptyIter;
impl Iterator for EmptyIter {
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> { None }
}
pub struct Empty;
impl Empty {
    pub fn iter(&self) -> EmptyIter { EmptyIter }
}
";

    fn check_assist_with_fixtures(before: &str, after: &str) {
        let before = &format!(
            "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
            before,
            EMPTY_ITER_FIXTURE,
            FamousDefs::FIXTURE,
        );
        check_assist(convert_iter_for_each_to_for, before, after);
    }

    #[test]
    fn test_for_each_in_method_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    });
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_in_method() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    })
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_in_iter_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty.iter();
    x.$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    });
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty.iter();
    for (x, y) in x {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_without_braces_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y)
    }
}
"#,
        )
    }
    #[test]
    fn test_for_each_not_applicable() {
        check_assist_not_applicable(
            convert_iter_for_each_to_for,
            r#"
fn main() {
    value.$0for_each(|x| println!("{}", x));
}"#,
        )
    }
}
<commit_msg>fix: replace doc-comments with normal comments<commit_after>use ide_db::helpers::FamousDefs;
use syntax::{
    ast::{self, edit::AstNodeEdit, make, ArgListOwner},
    AstNode,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_iter_for_each_to_for
//
// Converts an Iterator::for_each function into a for loop.
//
// ```rust
// fn main() {
//     let vec = vec![(1, 2), (2, 3), (3, 4)];
//     x.iter().for_each(|(x, y)| {
//         println!("x: {}, y: {}", x, y);
//     });
// }
// ```
// ->
// ```rust
// fn main() {
//     let vec = vec![(1, 2), (2, 3), (3, 4)];
//     for (x, y) in x.iter() {
//         println!("x: {}, y: {}", x, y);
//     }
// }
// ```
pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?;
    let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);

    let closure = match method.arg_list()?.args().next()? {
        ast::Expr::ClosureExpr(expr) => expr,
        _ => return None,
    };

    let (method, receiver) = validate_method_call_expr(&ctx.sema, method)?;

    let param_list = closure.param_list()?;
    let param = param_list.params().next()?.pat()?;
    let body = closure.body()?;

    let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());

    acc.add(
        AssistId("convert_iter_for_each_to_for", AssistKind::RefactorRewrite),
        "Replace this `Iterator::for_each` with a for loop",
        syntax.text_range(),
        |builder| {
            let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level());

            let block = match body {
                ast::Expr::BlockExpr(block) => block,
                _ => make::block_expr(Vec::new(), Some(body)),
            }
            .reset_indent()
            .indent(indent);

            let expr_for_loop = make::expr_for_loop(param, receiver, block);
            builder.replace(syntax.text_range(), expr_for_loop.syntax().text())
        },
    )
}

fn validate_method_call_expr(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    expr: ast::MethodCallExpr,
) -> Option<(ast::Expr, ast::Expr)> {
    if expr.name_ref()?.text() != "for_each" {
        return None;
    }

    let receiver = expr.receiver()?;
    let expr = ast::Expr::MethodCallExpr(expr);

    let it_type = sema.type_of_expr(&receiver)?;
    let module = sema.scope(receiver.syntax()).module()?;
    let krate = module.krate();

    let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
    it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, receiver))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    const EMPTY_ITER_FIXTURE: &'static str = r"
//- /lib.rs deps:core crate:empty_iter
pub struct EmptyIter;
impl Iterator for EmptyIter {
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> { None }
}
pub struct Empty;
impl Empty {
    pub fn iter(&self) -> EmptyIter { EmptyIter }
}
";

    fn check_assist_with_fixtures(before: &str, after: &str) {
        let before = &format!(
            "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
            before,
            EMPTY_ITER_FIXTURE,
            FamousDefs::FIXTURE,
        );
        check_assist(convert_iter_for_each_to_for, before, after);
    }

    #[test]
    fn test_for_each_in_method_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    });
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_in_method() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    })
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_in_iter_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty.iter();
    x.$0for_each(|(x, y)| {
        println!("x: {}, y: {}", x, y);
    });
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty.iter();
    for (x, y) in x {
        println!("x: {}, y: {}", x, y);
    }
}
"#,
        )
    }

    #[test]
    fn test_for_each_without_braces_stmt() {
        check_assist_with_fixtures(
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
}"#,
            r#"
use empty_iter::*;
fn main() {
    let x = Empty;
    for (x, y) in x.iter() {
        println!("x: {}, y: {}", x, y)
    }
}
"#,
        )
    }
    #[test]
    fn test_for_each_not_applicable() {
        check_assist_not_applicable(
            convert_iter_for_each_to_for,
            r#"
fn main() {
    value.$0for_each(|x| println!("{}", x));
}"#,
        )
    }
}
<|endoftext|>


<commit_before>use super::super::common::get_base_reward;
use super::validator_statuses::{TotalBalances, ValidatorStatus, ValidatorStatuses};
use super::Error;

use types::*;

/// Use to track the changes to a validators balance.
#[derive(Default, Clone)]
pub struct Delta {
    rewards: u64,
    penalties: u64,
}

impl Delta {
    /// Reward the validator with the `reward`.
    pub fn reward(&mut self, reward: u64) {
        self.rewards += reward;
    }

    /// Penalize the validator with the `penalty`.
    pub fn penalize(&mut self, penalty: u64) {
        self.penalties += penalty;
    }
}

impl std::ops::AddAssign for Delta {
    /// Use wrapping addition as that is how it's defined in the spec.
    fn add_assign(&mut self, other: Delta) {
        self.rewards += other.rewards;
        self.penalties += other.penalties;
    }
}

/// Apply attester and proposer rewards.
///
/// Spec v0.10.1
pub fn process_rewards_and_penalties<T: EthSpec>(
    state: &mut BeaconState<T>,
    validator_statuses: &mut ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    if state.current_epoch() == T::genesis_epoch() {
        return Ok(());
    }

    // Guard against an out-of-bounds during the validator balance update.
    if validator_statuses.statuses.len() != state.balances.len()
        || validator_statuses.statuses.len() != state.validators.len()
    {
        return Err(Error::ValidatorStatusesInconsistent);
    }

    let mut deltas = vec![Delta::default(); state.balances.len()];

    get_attestation_deltas(&mut deltas, state, &validator_statuses, spec)?;

    get_proposer_deltas(&mut deltas, state, validator_statuses, spec)?;

    // Apply the deltas, over-flowing but not under-flowing (saturating at 0 instead).
    for (i, delta) in deltas.iter().enumerate() {
        state.balances[i] += delta.rewards;
        state.balances[i] = state.balances[i].saturating_sub(delta.penalties);
    }

    Ok(())
}

/// For each attesting validator, reward the proposer who was first to include their attestation.
///
/// Spec v0.10.1
fn get_proposer_deltas<T: EthSpec>(
    deltas: &mut Vec<Delta>,
    state: &BeaconState<T>,
    validator_statuses: &mut ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    for (index, validator) in validator_statuses.statuses.iter().enumerate() {
        if validator.is_previous_epoch_attester && !validator.is_slashed {
            let inclusion = validator
                .inclusion_info
                .expect("It is a logic error for an attester not to have an inclusion delay.");

            let base_reward = get_base_reward(
                state,
                index,
                validator_statuses.total_balances.current_epoch,
                spec,
            )?;

            if inclusion.proposer_index >= deltas.len() {
                return Err(Error::ValidatorStatusesInconsistent);
            }

            deltas[inclusion.proposer_index].reward(base_reward / spec.proposer_reward_quotient);
        }
    }

    Ok(())
}

/// Apply rewards for participation in attestations during the previous epoch.
///
/// Spec v0.10.1
fn get_attestation_deltas<T: EthSpec>(
    deltas: &mut Vec<Delta>,
    state: &BeaconState<T>,
    validator_statuses: &ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let finality_delay = (state.previous_epoch() - state.finalized_checkpoint.epoch).as_u64();

    for (index, validator) in validator_statuses.statuses.iter().enumerate() {
        let base_reward = get_base_reward(
            state,
            index,
            validator_statuses.total_balances.current_epoch,
            spec,
        )?;

        let delta = get_attestation_delta::<T>(
            &validator,
            &validator_statuses.total_balances,
            base_reward,
            finality_delay,
            spec,
        );

        deltas[index] += delta;
    }

    Ok(())
}

/// Determine the delta for a single validator, sans proposer rewards.
///
/// Spec v0.10.1
fn get_attestation_delta<T: EthSpec>(
    validator: &ValidatorStatus,
    total_balances: &TotalBalances,
    base_reward: u64,
    finality_delay: u64,
    spec: &ChainSpec,
) -> Delta {
    let mut delta = Delta::default();

    // Is this validator eligible to be rewarded or penalized?
    // Spec: validator index in `eligible_validator_indices`
    let is_eligible = validator.is_active_in_previous_epoch
        || (validator.is_slashed && !validator.is_withdrawable_in_current_epoch);

    if !is_eligible {
        return delta;
    }

    let total_balance = total_balances.current_epoch;
    let total_attesting_balance = total_balances.previous_epoch_attesters;
    let matching_target_balance = total_balances.previous_epoch_target_attesters;
    let matching_head_balance = total_balances.previous_epoch_head_attesters;

    // Expected FFG source.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_source_attestations)`
    if validator.is_previous_epoch_attester && !validator.is_slashed {
        delta.reward(base_reward * total_attesting_balance / total_balance);
        // Inclusion speed bonus
        let proposer_reward = base_reward / spec.proposer_reward_quotient;
        let max_attester_reward = base_reward - proposer_reward;
        let inclusion = validator
            .inclusion_info
            .expect("It is a logic error for an attester not to have an inclusion delay.");
        delta.reward(max_attester_reward / inclusion.delay);
    } else {
        delta.penalize(base_reward);
    }

    // Expected FFG target.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_target_attestations)`
    if validator.is_previous_epoch_target_attester && !validator.is_slashed {
        delta.reward(base_reward * matching_target_balance / total_balance);
    } else {
        delta.penalize(base_reward);
    }

    // Expected head.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_head_attestations)`
    if validator.is_previous_epoch_head_attester && !validator.is_slashed {
        delta.reward(base_reward * matching_head_balance / total_balance);
    } else {
        delta.penalize(base_reward);
    }

    // Inactivity penalty
    if finality_delay > spec.min_epochs_to_inactivity_penalty {
        // All eligible validators are penalized
        delta.penalize(spec.base_rewards_per_epoch * base_reward);

        // Additionally, all validators whose FFG target didn't match are penalized extra
        if !validator.is_previous_epoch_target_attester {
            delta.penalize(
                validator.current_epoch_effective_balance * finality_delay
                    / spec.inactivity_penalty_quotient,
            );
        }
    }

    // Proposer bonus is handled in `get_proposer_deltas`.
    //
    // This function only computes the delta for a single validator, so it cannot also return a
    // delta for a validator.

    delta
}
<commit_msg>Update reward calculations to v0.11.0 - Handle u64 overflow (#920) (#921)<commit_after>use super::super::common::get_base_reward;
use super::validator_statuses::{TotalBalances, ValidatorStatus, ValidatorStatuses};
use super::Error;

use types::*;

/// Use to track the changes to a validators balance.
#[derive(Default, Clone)]
pub struct Delta {
    rewards: u64,
    penalties: u64,
}

impl Delta {
    /// Reward the validator with the `reward`.
    pub fn reward(&mut self, reward: u64) {
        self.rewards += reward;
    }

    /// Penalize the validator with the `penalty`.
    pub fn penalize(&mut self, penalty: u64) {
        self.penalties += penalty;
    }
}

impl std::ops::AddAssign for Delta {
    /// Use wrapping addition as that is how it's defined in the spec.
    fn add_assign(&mut self, other: Delta) {
        self.rewards += other.rewards;
        self.penalties += other.penalties;
    }
}

/// Apply attester and proposer rewards.
///
/// Spec v0.10.1
pub fn process_rewards_and_penalties<T: EthSpec>(
    state: &mut BeaconState<T>,
    validator_statuses: &mut ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    if state.current_epoch() == T::genesis_epoch() {
        return Ok(());
    }

    // Guard against an out-of-bounds during the validator balance update.
    if validator_statuses.statuses.len() != state.balances.len()
        || validator_statuses.statuses.len() != state.validators.len()
    {
        return Err(Error::ValidatorStatusesInconsistent);
    }

    let mut deltas = vec![Delta::default(); state.balances.len()];

    get_attestation_deltas(&mut deltas, state, &validator_statuses, spec)?;

    get_proposer_deltas(&mut deltas, state, validator_statuses, spec)?;

    // Apply the deltas, over-flowing but not under-flowing (saturating at 0 instead).
    for (i, delta) in deltas.iter().enumerate() {
        state.balances[i] += delta.rewards;
        state.balances[i] = state.balances[i].saturating_sub(delta.penalties);
    }

    Ok(())
}

/// For each attesting validator, reward the proposer who was first to include their attestation.
///
/// Spec v0.10.1
fn get_proposer_deltas<T: EthSpec>(
    deltas: &mut Vec<Delta>,
    state: &BeaconState<T>,
    validator_statuses: &mut ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    for (index, validator) in validator_statuses.statuses.iter().enumerate() {
        if validator.is_previous_epoch_attester && !validator.is_slashed {
            let inclusion = validator
                .inclusion_info
                .expect("It is a logic error for an attester not to have an inclusion delay.");

            let base_reward = get_base_reward(
                state,
                index,
                validator_statuses.total_balances.current_epoch,
                spec,
            )?;

            if inclusion.proposer_index >= deltas.len() {
                return Err(Error::ValidatorStatusesInconsistent);
            }

            deltas[inclusion.proposer_index].reward(base_reward / spec.proposer_reward_quotient);
        }
    }

    Ok(())
}

/// Apply rewards for participation in attestations during the previous epoch.
///
/// Spec v0.10.1
fn get_attestation_deltas<T: EthSpec>(
    deltas: &mut Vec<Delta>,
    state: &BeaconState<T>,
    validator_statuses: &ValidatorStatuses,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let finality_delay = (state.previous_epoch() - state.finalized_checkpoint.epoch).as_u64();

    for (index, validator) in validator_statuses.statuses.iter().enumerate() {
        let base_reward = get_base_reward(
            state,
            index,
            validator_statuses.total_balances.current_epoch,
            spec,
        )?;

        let delta = get_attestation_delta::<T>(
            &validator,
            &validator_statuses.total_balances,
            base_reward,
            finality_delay,
            spec,
        );

        deltas[index] += delta;
    }

    Ok(())
}

/// Determine the delta for a single validator, sans proposer rewards.
///
/// Spec v0.11.0
fn get_attestation_delta<T: EthSpec>(
    validator: &ValidatorStatus,
    total_balances: &TotalBalances,
    base_reward: u64,
    finality_delay: u64,
    spec: &ChainSpec,
) -> Delta {
    let mut delta = Delta::default();

    // Is this validator eligible to be rewarded or penalized?
    // Spec: validator index in `eligible_validator_indices`
    let is_eligible = validator.is_active_in_previous_epoch
        || (validator.is_slashed && !validator.is_withdrawable_in_current_epoch);

    if !is_eligible {
        return delta;
    }

    // Handle integer overflow by dividing these quantities by EFFECTIVE_BALANCE_INCREMENT
    // Spec:
    // - increment = EFFECTIVE_BALANCE_INCREMENT
    // - reward_numerator = get_base_reward(state, index) * (attesting_balance // increment)
    // - rewards[index] = reward_numerator // (total_balance // increment)
    let total_balance_ebi = total_balances.current_epoch / spec.effective_balance_increment;
    let total_attesting_balance_ebi =
        total_balances.previous_epoch_attesters / spec.effective_balance_increment;
    let matching_target_balance_ebi =
        total_balances.previous_epoch_target_attesters / spec.effective_balance_increment;
    let matching_head_balance_ebi =
        total_balances.previous_epoch_head_attesters / spec.effective_balance_increment;

    // Expected FFG source.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_source_attestations)`
    if validator.is_previous_epoch_attester && !validator.is_slashed {
        delta.reward(base_reward * total_attesting_balance_ebi / total_balance_ebi);
        // Inclusion speed bonus
        let proposer_reward = base_reward / spec.proposer_reward_quotient;
        let max_attester_reward = base_reward - proposer_reward;
        let inclusion = validator
            .inclusion_info
            .expect("It is a logic error for an attester not to have an inclusion delay.");
        delta.reward(max_attester_reward / inclusion.delay);
    } else {
        delta.penalize(base_reward);
    }

    // Expected FFG target.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_target_attestations)`
    if validator.is_previous_epoch_target_attester && !validator.is_slashed {
        delta.reward(base_reward * matching_target_balance_ebi / total_balance_ebi);
    } else {
        delta.penalize(base_reward);
    }

    // Expected head.
    // Spec:
    // - validator index in `get_unslashed_attesting_indices(state, matching_head_attestations)`
    if validator.is_previous_epoch_head_attester && !validator.is_slashed {
        delta.reward(base_reward * matching_head_balance_ebi / total_balance_ebi);
    } else {
        delta.penalize(base_reward);
    }

    // Inactivity penalty
    if finality_delay > spec.min_epochs_to_inactivity_penalty {
        // All eligible validators are penalized
        delta.penalize(spec.base_rewards_per_epoch * base_reward);

        // Additionally, all validators whose FFG target didn't match are penalized extra
        if !validator.is_previous_epoch_target_attester {
            delta.penalize(
                validator.current_epoch_effective_balance * finality_delay
                    / spec.inactivity_penalty_quotient,
            );
        }
    }

    // Proposer bonus is handled in `get_proposer_deltas`.
    //
    // This function only computes the delta for a single validator, so it cannot also return a
    // delta for a validator.

    delta
}
<|endoftext|>


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

use super::*;
use crate::LibraDB;
use crypto::hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH};
use tempfile::tempdir;
use types::{
    account_address::{AccountAddress, ADDRESS_LENGTH},
    account_state_blob::AccountStateBlob,
    proof::verify_sparse_merkle_element,
};

fn put_account_state_set(
    store: &StateStore,
    account_state_set: Vec<(AccountAddress, AccountStateBlob)>,
    first_version: Version,
    root_hash: HashValue,
    batch: &mut SchemaBatch,
) -> HashValue {
    store
        .put_account_state_sets(
            vec![account_state_set.into_iter().collect::<HashMap<_, _>>()],
            first_version,
            root_hash,
            batch,
        )
        .unwrap()[0]
}

#[test]
fn test_empty_store() {
    let tmp_dir = tempdir().unwrap();
    let db = LibraDB::new(&tmp_dir);
    let store = &db.state_store;
    let address = AccountAddress::new([1u8; ADDRESS_LENGTH]);
    let root = *SPARSE_MERKLE_PLACEHOLDER_HASH;
    let (value, proof) = store
        .get_account_state_with_proof_by_state_root(address, root)
        .unwrap();
    assert!(value.is_none());
    assert!(verify_sparse_merkle_element(root, address.hash(), &None, &proof).is_ok());
}

#[test]
fn test_state_store_reader_writer() {
    let tmp_dir = tempdir().unwrap();
    let db = LibraDB::new(&tmp_dir);
    let store = &db.state_store;
    let address1 = AccountAddress::new([1u8; ADDRESS_LENGTH]);
    let address2 = AccountAddress::new([2u8; ADDRESS_LENGTH]);
    let address3 = AccountAddress::new([3u8; ADDRESS_LENGTH]);
    let value1 = AccountStateBlob::from(vec![0x01]);
    let value1_update = AccountStateBlob::from(vec![0x00]);
    let value2 = AccountStateBlob::from(vec![0x02]);
    let value3 = AccountStateBlob::from(vec![0x03]);
    let mut root = *SPARSE_MERKLE_PLACEHOLDER_HASH;

    // Verify initial states.
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address1, root)
            .unwrap();
        assert!(value.is_none());
        assert!(verify_sparse_merkle_element(root, address1.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address2, root)
            .unwrap();
        assert!(value.is_none());
        assert!(verify_sparse_merkle_element(root, address2.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address3, root)
            .unwrap();
        assert!(value.is_none());
        assert!(verify_sparse_merkle_element(root, address3.hash(), &value, &proof).is_ok());
    }

    // Insert address1 with value 1 and verify new states.
    let mut batch1 = SchemaBatch::new();
    root = put_account_state_set(
        &store,
        vec![(address1, value1.clone())],
        0, /* version */
        root,
        &mut batch1,
    );
    db.commit(batch1).unwrap();
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address1, root)
            .unwrap();
        assert_eq!(value, Some(value1));
        assert!(verify_sparse_merkle_element(root, address1.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address2, root)
            .unwrap();
        assert!(value.is_none());
        assert!(verify_sparse_merkle_element(root, address2.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address3, root)
            .unwrap();
        assert!(value.is_none());
        assert!(verify_sparse_merkle_element(root, address3.hash(), &value, &proof).is_ok());
    }

    // Insert address 1 with updated value1, address2 with value 2 and address3 with value3 and
    // verify new states.
    let mut batch2 = SchemaBatch::new();
    root = put_account_state_set(
        &store,
        vec![
            (address1, value1_update.clone()),
            (address2, value2.clone()),
            (address3, value3.clone()),
        ],
        1, /* version */
        root,
        &mut batch2,
    );
    db.commit(batch2).unwrap();
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address1, root)
            .unwrap();
        assert_eq!(value, Some(value1_update));
        assert!(verify_sparse_merkle_element(root, address1.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address2, root)
            .unwrap();
        assert_eq!(value, Some(value2));
        assert!(verify_sparse_merkle_element(root, address2.hash(), &value, &proof).is_ok());
    }
    {
        let (value, proof) = store
            .get_account_state_with_proof_by_state_root(address3, root)
            .unwrap();
        assert_eq!(value, Some(value3));
        assert!(verify_sparse_merkle_element(root, address3.hash(), &value, &proof).is_ok());
    }
}
<commit_msg>[Storage] refactor state_store_test.rs to make it more concise<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::*;
use crate::LibraDB;
use crypto::hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH};
use tempfile::tempdir;
use types::{
    account_address::{AccountAddress, ADDRESS_LENGTH},
    account_state_blob::AccountStateBlob,
    proof::verify_sparse_merkle_element,
};

fn put_account_state_set(
    db: &LibraDB,
    account_state_set: Vec<(AccountAddress, AccountStateBlob)>,
    version: Version,
    root_hash: HashValue,
) -> HashValue {
    let mut batch = SchemaBatch::new();
    let root = db
        .state_store
        .put_account_state_sets(
            vec![account_state_set.into_iter().collect::<HashMap<_, _>>()],
            version,
            root_hash,
            &mut batch,
        )
        .unwrap()[0];
    db.commit(batch).unwrap();

    root
}

fn verify_state_in_store(
    store: &StateStore,
    address: AccountAddress,
    expected_value: Option<&AccountStateBlob>,
    root: HashValue,
) {
    let (value, proof) = store
        .get_account_state_with_proof_by_state_root(address, root)
        .unwrap();
    assert_eq!(value.as_ref(), expected_value);
    verify_sparse_merkle_element(root, address.hash(), &value, &proof).unwrap();
}

#[test]
fn test_empty_store() {
    let tmp_dir = tempdir().unwrap();
    let db = LibraDB::new(&tmp_dir);
    let store = &db.state_store;
    let address = AccountAddress::new([1u8; ADDRESS_LENGTH]);
    let root = *SPARSE_MERKLE_PLACEHOLDER_HASH;
    let (value, proof) = store
        .get_account_state_with_proof_by_state_root(address, root)
        .unwrap();
    assert!(value.is_none());
    assert!(verify_sparse_merkle_element(root, address.hash(), &None, &proof).is_ok());
}

#[test]
fn test_state_store_reader_writer() {
    let tmp_dir = tempdir().unwrap();
    let db = LibraDB::new(&tmp_dir);
    let store = &db.state_store;
    let address1 = AccountAddress::new([1u8; ADDRESS_LENGTH]);
    let address2 = AccountAddress::new([2u8; ADDRESS_LENGTH]);
    let address3 = AccountAddress::new([3u8; ADDRESS_LENGTH]);
    let value1 = AccountStateBlob::from(vec![0x01]);
    let value1_update = AccountStateBlob::from(vec![0x00]);
    let value2 = AccountStateBlob::from(vec![0x02]);
    let value3 = AccountStateBlob::from(vec![0x03]);
    let mut root = *SPARSE_MERKLE_PLACEHOLDER_HASH;

    // Verify initial states.
    verify_state_in_store(&store, address1, None, root);
    verify_state_in_store(&store, address2, None, root);
    verify_state_in_store(&store, address3, None, root);

    // Insert address1 with value 1 and verify new states.
    root = put_account_state_set(
        &db,
        vec![(address1, value1.clone())],
        0, /* version */
        root,
    );
    verify_state_in_store(&store, address1, Some(&value1), root);
    verify_state_in_store(&store, address2, None, root);
    verify_state_in_store(&store, address3, None, root);

    // Insert address 1 with updated value1, address2 with value 2 and address3 with value3 and
    // verify new states.
    root = put_account_state_set(
        &db,
        vec![
            (address1, value1_update.clone()),
            (address2, value2.clone()),
            (address3, value3.clone()),
        ],
        1, /* version */
        root,
    );
    verify_state_in_store(&store, address1, Some(&value1_update), root);
    verify_state_in_store(&store, address2, Some(&value2), root);
    verify_state_in_store(&store, address3, Some(&value3), root);
}
<|endoftext|>


<commit_before>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use std::path;

use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;
use glam::Quat;

use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;
use crate::{conf, filesystem};

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
///
/// Note that if the canvas is not of the same size as the screen, and you want
/// to render using coordinates relative to the canvas' coordinate system, you
/// need to call [`graphics::set_screen_coordinates`](fn.set_screen_coordinates.html)
/// and pass in a rectangle with position (0, 0) and a size equal to that of the
/// canvas.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    #[allow(clippy::new_ret_no_self)]
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s.into()),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to. Note that this will be flipped but otherwise the same, use the [`to_image`](#method.to_image) function for the unflipped version.
    pub fn raw_image(&self) -> &Image {
        &self.image
    }

    /// Creates an `Image` with the content of its raw counterpart but transformed to behave like a normal `Image`.
    pub fn to_image(&self, ctx: &mut Context) -> GameResult<Image> {
        let pixel_data = self.to_rgba8(ctx)?;
        Image::from_rgba8(ctx, self.image.width, self.image.height, &pixel_data)
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Dumps the flipped `Canvas`'s data to a `Vec` of `u8` RBGA8 values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        let mut pixel_data = self.image.to_rgba8(ctx)?;
        flip_pixel_data(
            &mut pixel_data,
            self.image.width as usize,
            self.image.height as usize,
        );
        Ok(pixel_data)
    }

    /// Encode the `Canvas`'s content to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = ::image::ColorType::Rgba8;
        match format {
            ImageFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width()),
                    u32::from(self.height()),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// Return the width of the canvas.
    pub fn width(&self) -> u16 {
        self.image.width
    }

    /// Return the height of the canvas.
    pub fn height(&self) -> u16 {
        self.image.height
    }

    /// Returns the dimensions of the canvas.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Get the filter mode for the canvas.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let scale_x = param.src.w * self.width() as f32;
        let scale_y = param.src.h * self.height() as f32;

        let param = param.transform(
            glam::Mat4::from(param.trans.to_bare_matrix())
                * Matrix4::from_scale(glam::vec3(scale_x, scale_y, 1.0)),
        );

        let new_param = flip_draw_param_vertical(param);

        image::draw_image_raw(&self.image, ctx, new_param)
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

fn flip_draw_param_vertical(param: DrawParam) -> DrawParam {
    let param = if let Transform::Matrix(mat) = param.trans {
        param.transform(
            glam::Mat4::from(mat)
                * glam::Mat4::from_scale_rotation_translation(
                    glam::vec3(1.0, -1.0, 1.0),
                    Quat::identity(),
                    glam::vec3(0.0, 1.0, 0.0),
                ),
        )
    } else {
        panic!("Can not be called with a non-matrix DrawParam");
    };
    let new_src = Rect {
        x: param.src.x,
        y: (1.0 - param.src.h) - param.src.y,
        w: param.src.w,
        h: param.src.h,
    };
    param.src(new_src)
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<commit_msg>Use from instead of as<commit_after>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use std::path;

use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;
use glam::Quat;

use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;
use crate::{conf, filesystem};

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
///
/// Note that if the canvas is not of the same size as the screen, and you want
/// to render using coordinates relative to the canvas' coordinate system, you
/// need to call [`graphics::set_screen_coordinates`](fn.set_screen_coordinates.html)
/// and pass in a rectangle with position (0, 0) and a size equal to that of the
/// canvas.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    #[allow(clippy::new_ret_no_self)]
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s.into()),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to. Note that this will be flipped but otherwise the same, use the [`to_image`](#method.to_image) function for the unflipped version.
    pub fn raw_image(&self) -> &Image {
        &self.image
    }

    /// Creates an `Image` with the content of its raw counterpart but transformed to behave like a normal `Image`.
    pub fn to_image(&self, ctx: &mut Context) -> GameResult<Image> {
        let pixel_data = self.to_rgba8(ctx)?;
        Image::from_rgba8(ctx, self.image.width, self.image.height, &pixel_data)
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Dumps the flipped `Canvas`'s data to a `Vec` of `u8` RBGA8 values.
    pub fn to_rgba8(&self, ctx: &mut Context) -> GameResult<Vec<u8>> {
        let mut pixel_data = self.image.to_rgba8(ctx)?;
        flip_pixel_data(
            &mut pixel_data,
            self.image.width as usize,
            self.image.height as usize,
        );
        Ok(pixel_data)
    }

    /// Encode the `Canvas`'s content to the given file format and
    /// write it out to the given path.
    ///
    /// See the [`filesystem`](../filesystem/index.html) module docs for where exactly
    /// the file will end up.
    pub fn encode<P: AsRef<path::Path>>(
        &self,
        ctx: &mut Context,
        format: ImageFormat,
        path: P,
    ) -> GameResult {
        use std::io;
        let data = self.to_rgba8(ctx)?;
        let f = filesystem::create(ctx, path)?;
        let writer = &mut io::BufWriter::new(f);
        let color_format = ::image::ColorType::Rgba8;
        match format {
            ImageFormat::Png => ::image::png::PngEncoder::new(writer)
                .encode(
                    &data,
                    u32::from(self.width()),
                    u32::from(self.height()),
                    color_format,
                )
                .map_err(Into::into),
        }
    }

    /// Return the width of the canvas.
    pub fn width(&self) -> u16 {
        self.image.width
    }

    /// Return the height of the canvas.
    pub fn height(&self) -> u16 {
        self.image.height
    }

    /// Returns the dimensions of the canvas.
    pub fn dimensions(&self) -> Rect {
        Rect::new(0.0, 0.0, f32::from(self.width()), f32::from(self.height()))
    }

    /// Get the filter mode for the canvas.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);

        // We have to mess with the scale to make everything
        // be its-unit-size-in-pixels.
        let scale_x = param.src.w * f32::from(self.width());
        let scale_y = param.src.h * f32::from(self.height());

        let param = param.transform(
            glam::Mat4::from(param.trans.to_bare_matrix())
                * Matrix4::from_scale(glam::vec3(scale_x, scale_y, 1.0)),
        );

        let new_param = flip_draw_param_vertical(param);

        image::draw_image_raw(&self.image, ctx, new_param)
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

fn flip_draw_param_vertical(param: DrawParam) -> DrawParam {
    let param = if let Transform::Matrix(mat) = param.trans {
        param.transform(
            glam::Mat4::from(mat)
                * glam::Mat4::from_scale_rotation_translation(
                    glam::vec3(1.0, -1.0, 1.0),
                    Quat::identity(),
                    glam::vec3(0.0, 1.0, 0.0),
                ),
        )
    } else {
        panic!("Can not be called with a non-matrix DrawParam");
    };
    let new_src = Rect {
        x: param.src.x,
        y: (1.0 - param.src.h) - param.src.y,
        w: param.src.w,
        h: param.src.h,
    };
    param.src(new_src)
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.

extern crate libc;
extern crate time;

use std::io::timer::Timer;
use std::mem;
use std::sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL};
use std::sync::atomics;
use std::time::duration::Duration;

#[cfg(all(unix, not(test)))]
fn main()
{
    use libc::consts::os::posix88::SIGINT;
    use libc::funcs::posix01::signal;

    // The time between ticks of our counter.
    let duration = Duration::seconds(1) / 2;
    let mut timer = Timer::new().unwrap();
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = INIT_ATOMIC_BOOL;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, atomics::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, atomics::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    let periodic = timer.periodic(duration);
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    for _ in periodic.iter() {
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(atomics::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<commit_msg>Avoiding unused imports warning on Windows.<commit_after>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.

extern crate libc;
extern crate time;

#[cfg(all(unix, not(test)))]
fn main()
{
    use libc::consts::os::posix88::SIGINT;
    use libc::funcs::posix01::signal;
    use std::io::timer::Timer;
    use std::mem;
    use std::sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL};
    use std::sync::atomics;
    use std::time::duration::Duration;

    // The time between ticks of our counter.
    let duration = Duration::seconds(1) / 2;
    let mut timer = Timer::new().unwrap();
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = INIT_ATOMIC_BOOL;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, atomics::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, atomics::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    let periodic = timer.periodic(duration);
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    for _ in periodic.iter() {
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(atomics::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    server::LSPState,
};
use common::{Named, PerfLogger};
use interner::Intern;
use lsp_types::request::Request;
use schema::Schema;
use schema_documentation::SchemaDocumentation;
use serde::{Deserialize, Serialize};

pub(crate) enum SearchSchemaItems {}

#[derive(Deserialize, Serialize)]
pub(crate) struct TypeDescription {
    name: String,
    description: Option<String>,
}

#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SchemaSearchItemsResponse {
    pub items: Vec<TypeDescription>,
    pub has_more: bool,
}

#[derive(Deserialize, Serialize)]
pub(crate) struct SearchSchemaItemsParams {
    pub filter: Option<String>,
    pub schema_name: String,
    pub take: Option<usize>,
    pub skip: Option<usize>,
}

impl Request for SearchSchemaItems {
    type Params = SearchSchemaItemsParams;
    type Result = SchemaSearchItemsResponse;
    const METHOD: &'static str = "relay/searchSchemaItems";
}

pub(crate) fn on_search_schema_items<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: SearchSchemaItemsParams,
) -> LSPRuntimeResult<<SearchSchemaItems as Request>::Result> {
    let filter = params.filter.map(|f| f.to_lowercase());
    let schema_name: &str = &params.schema_name;
    let schemas = state.get_schemas();
    let schema = schemas
        .get(&schema_name.intern())
        .ok_or(LSPRuntimeError::ExpectedError)?;
    let schema_documentation = state.get_schema_documentation(schema_name);

    let objects = filter_and_transform_items(schema.objects(), &schema_documentation, &filter);
    let interfaces =
        filter_and_transform_items(schema.interfaces(), &schema_documentation, &filter);
    let enums = filter_and_transform_items(schema.enums(), &schema_documentation, &filter);
    let unions = filter_and_transform_items(schema.unions(), &schema_documentation, &filter);
    let input_objects =
        filter_and_transform_items(schema.input_objects(), &schema_documentation, &filter);
    let scalars = filter_and_transform_items(schema.scalars(), &schema_documentation, &filter);

    let mut items = objects
        .chain(interfaces)
        .chain(enums)
        .chain(unions)
        .chain(input_objects)
        .chain(scalars)
        .collect::<Vec<_>>();

    items.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));

    let skip = *params.skip.as_ref().unwrap_or(&0);
    let take = *params.take.as_ref().unwrap_or(&500);
    let has_more = items.len() > skip + take;

    let items = items.into_iter().skip(skip).take(take).collect::<Vec<_>>();

    Ok(SchemaSearchItemsResponse { items, has_more })
}

fn filter_and_transform_items<'a, T: Named + 'a>(
    items: impl Iterator<Item = &'a T> + 'a,
    schema_documentation: &'a impl SchemaDocumentation,
    filter: &'a Option<String>,
) -> impl Iterator<Item = TypeDescription> + 'a {
    items.filter_map(move |obj| {
        let name = obj.name().lookup();
        let description = schema_documentation
            .get_type_description(name)
            .map(|s| s.to_string());

        if should_include_named_item(name, &description, filter) {
            Some(TypeDescription {
                name: name.to_string(),
                description,
            })
        } else {
            None
        }
    })
}

fn should_include_named_item(
    name: &str,
    description: &Option<String>,
    filter: &Option<String>,
) -> bool {
    if let Some(filter) = filter.as_ref() {
        if name.to_lowercase().contains(filter) {
            true
        } else if let Some(description) = description {
            description.to_lowercase().contains(filter)
        } else {
            false
        }
    } else {
        true
    }
}

#[cfg(test)]
mod tests {
    use crate::search_schema_items::should_include_named_item;

    #[test]
    fn test_no_filter() {
        assert_eq!(
            should_include_named_item("Yohan Blake", &Some("London 2012".to_string()), &None),
            true
        );
        assert_eq!(should_include_named_item("Usain Bolt", &None, &None), true);
    }

    #[test]
    fn test_filter_matches_name() {
        assert_eq!(
            should_include_named_item("Michael Frater", &None, &Some("michael".to_string())),
            true
        );
        assert_eq!(
            should_include_named_item(
                "Nesta Carter",
                &Some("London 2012".to_string()),
                &Some("nesta".to_string())
            ),
            true
        );
    }

    #[test]
    fn test_filter_matches_description() {
        assert_eq!(
            should_include_named_item(
                "Tiana Bartoletta",
                &Some("London 2012".to_string()),
                &Some("london".to_string())
            ),
            true
        );
    }

    #[test]
    fn test_non_matching_filter() {
        assert_eq!(
            should_include_named_item(
                "Allyson Felix",
                &Some("London 2012".to_string()),
                &Some("salt lake city".to_string())
            ),
            false
        );
    }
}
<commit_msg>Rename structs to be more meaningful<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::{
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    server::LSPState,
};
use common::{Named, PerfLogger};
use interner::Intern;
use lsp_types::request::Request;
use schema::Schema;
use schema_documentation::SchemaDocumentation;
use serde::{Deserialize, Serialize};

pub(crate) enum SearchSchemaItems {}

#[derive(Deserialize, Serialize)]
pub(crate) struct SchemaSearchItem {
    name: String,
    description: Option<String>,
}

#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SearchSchemaItemsResponse {
    pub items: Vec<SchemaSearchItem>,
    pub has_more: bool,
}

#[derive(Deserialize, Serialize)]
pub(crate) struct SearchSchemaItemsParams {
    pub filter: Option<String>,
    pub schema_name: String,
    pub take: Option<usize>,
    pub skip: Option<usize>,
}

impl Request for SearchSchemaItems {
    type Params = SearchSchemaItemsParams;
    type Result = SearchSchemaItemsResponse;
    const METHOD: &'static str = "relay/searchSchemaItems";
}

pub(crate) fn on_search_schema_items<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: SearchSchemaItemsParams,
) -> LSPRuntimeResult<<SearchSchemaItems as Request>::Result> {
    let filter = params.filter.map(|f| f.to_lowercase());
    let schema_name: &str = &params.schema_name;
    let schemas = state.get_schemas();
    let schema = schemas
        .get(&schema_name.intern())
        .ok_or(LSPRuntimeError::ExpectedError)?;
    let schema_documentation = state.get_schema_documentation(schema_name);

    let objects = filter_and_transform_items(schema.objects(), &schema_documentation, &filter);
    let interfaces =
        filter_and_transform_items(schema.interfaces(), &schema_documentation, &filter);
    let enums = filter_and_transform_items(schema.enums(), &schema_documentation, &filter);
    let unions = filter_and_transform_items(schema.unions(), &schema_documentation, &filter);
    let input_objects =
        filter_and_transform_items(schema.input_objects(), &schema_documentation, &filter);
    let scalars = filter_and_transform_items(schema.scalars(), &schema_documentation, &filter);

    let mut items = objects
        .chain(interfaces)
        .chain(enums)
        .chain(unions)
        .chain(input_objects)
        .chain(scalars)
        .collect::<Vec<_>>();

    items.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));

    let skip = *params.skip.as_ref().unwrap_or(&0);
    let take = *params.take.as_ref().unwrap_or(&500);
    let has_more = items.len() > skip + take;

    let items = items.into_iter().skip(skip).take(take).collect::<Vec<_>>();

    Ok(SearchSchemaItemsResponse { items, has_more })
}

fn filter_and_transform_items<'a, T: Named + 'a>(
    items: impl Iterator<Item = &'a T> + 'a,
    schema_documentation: &'a impl SchemaDocumentation,
    filter: &'a Option<String>,
) -> impl Iterator<Item = SchemaSearchItem> + 'a {
    items.filter_map(move |obj| {
        let name = obj.name().lookup();
        let description = schema_documentation
            .get_type_description(name)
            .map(|s| s.to_string());

        if should_include_named_item(name, &description, filter) {
            Some(SchemaSearchItem {
                name: name.to_string(),
                description,
            })
        } else {
            None
        }
    })
}

fn should_include_named_item(
    name: &str,
    description: &Option<String>,
    filter: &Option<String>,
) -> bool {
    if let Some(filter) = filter.as_ref() {
        if name.to_lowercase().contains(filter) {
            true
        } else if let Some(description) = description {
            description.to_lowercase().contains(filter)
        } else {
            false
        }
    } else {
        true
    }
}

#[cfg(test)]
mod tests {
    use crate::search_schema_items::should_include_named_item;

    #[test]
    fn test_no_filter() {
        assert_eq!(
            should_include_named_item("Yohan Blake", &Some("London 2012".to_string()), &None),
            true
        );
        assert_eq!(should_include_named_item("Usain Bolt", &None, &None), true);
    }

    #[test]
    fn test_filter_matches_name() {
        assert_eq!(
            should_include_named_item("Michael Frater", &None, &Some("michael".to_string())),
            true
        );
        assert_eq!(
            should_include_named_item(
                "Nesta Carter",
                &Some("London 2012".to_string()),
                &Some("nesta".to_string())
            ),
            true
        );
    }

    #[test]
    fn test_filter_matches_description() {
        assert_eq!(
            should_include_named_item(
                "Tiana Bartoletta",
                &Some("London 2012".to_string()),
                &Some("london".to_string())
            ),
            true
        );
    }

    #[test]
    fn test_non_matching_filter() {
        assert_eq!(
            should_include_named_item(
                "Allyson Felix",
                &Some("London 2012".to_string()),
                &Some("salt lake city".to_string())
            ),
            false
        );
    }
}
<|endoftext|>