<commit_before>/// The Validator Client service.
///
/// Connects to a beacon node and negotiates the correct chain id.
///
/// Once connected, the service loads known validators keypairs from disk. Every slot,
/// the service pings the beacon node, asking for new duties for each of the validators.
///
/// When a validator needs to either produce a block or sign an attestation, it requests the
/// data from the beacon node and performs the signing before publishing the block to the beacon
/// node.
//use crate::attester_service::{AttestationGrpcClient, AttesterService};
use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer};
use crate::config::Config as ValidatorConfig;
use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap, UpdateOutcome};
use crate::error as error_chain;
use crate::error::ErrorKind;
use crate::signer::Signer;
use attester::test_utils::EpochMap;
use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester};
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{debug, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::sync::RwLock;
use std::thread;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::test_utils::generate_deterministic_keypairs;
use types::{ChainSpec, Epoch, Fork, Slot};

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
//TODO: Generalize the BeaconNode types to use testing
pub struct Service<B: BeaconNodeDuties + 'static, S: Signer + 'static> {
    /// The node's current fork version we are processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// The chain specification for this clients instance.
    spec: Arc<ChainSpec>,
    /// The duties manager which maintains the state of when to perform actions.
    duties_manager: Arc<DutiesManager<B, S>>,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockGrpcClient>,
    /// The attester GRPC client.
    attester_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Service<ValidatorServiceClient, Keypair>> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            BeaconNodeServiceClient::new(ch)
        };

        // retrieve node information and validate the beacon node
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    // verify the node's genesis time
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    // verify the node's chain id
                    if config.spec.chain_id != info.chain_id as u8 {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", config.spec.chain_id, info.chain_id).into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
            // a wrapper around the service client to implement the beacon block node trait
            Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attester_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock =
            SystemTimeSlotClock::new(genesis_slot, genesis_time, config.spec.seconds_per_slot)
                .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        /* Generate the duties manager */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = Arc::new(generate_deterministic_keypairs(8));

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let duties_manager = Arc::new(DutiesManager {
            duties_map,
            // these are abstract objects capable of signing
            signers: keypairs,
            beacon_node: validator_client,
        });

        let spec = Arc::new(config.spec);

        Ok(Service {
            fork,
            slot_clock,
            current_slot,
            spec,
            duties_manager,
            beacon_block_client,
            attester_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    // TODO: Improve handling of generic BeaconNode types, to stub grpcClient
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let mut service =
            Service::<ValidatorServiceClient, Keypair>::initialize_service(config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .map_err(|e| format!("System clock error: {:?}", e))?
            .expect("Cannot start before genesis");

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(service.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(Instant::now() + duration_to_next_slot, slot_duration)
        };

        /* kick off the core service */
        runtime.block_on(
            interval
                .for_each(move |_| {
                    // if a non-fatal error occurs, proceed to the next slot.
                    let _ignore_error = service.per_slot_execution();
                    // completed a slot process
                    Ok(())
                })
                .map_err(|e| format!("Service thread failed: {:?}", e)),
        )?;
        // validator client exited
        Ok(())
    }

    /// The execution logic that runs every slot.
    // Errors are logged to output, and core execution continues unless fatal errors occur.
    fn per_slot_execution(&mut self) -> error_chain::Result<()> {
        /* get the new current slot and epoch */
        self.update_current_slot()?;

        /* check for new duties */
        self.check_for_duties();

        /* process any required duties for validators */
        self.process_duties();

        Ok(())
    }

    /// Updates the known current slot and epoch.
    fn update_current_slot(&mut self) -> error_chain::Result<()> {
        let current_slot = match self.slot_clock.present_slot() {
            Err(e) => {
                error!(self.log, "SystemTimeError {:?}", e);
                return Err("Could not read system time".into());
            }
            Ok(slot) => slot.expect("Genesis is in the future"),
        };

        let current_epoch = current_slot.epoch(self.spec.slots_per_epoch);

        // this is a fatal error. If the slot clock repeats, there is something wrong with
        // the timer, terminate immediately.
        assert!(
            current_slot > self.current_slot,
            "The Timer should poll a new slot"
        );
        self.current_slot = current_slot;
        info!(self.log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64());
        Ok(())
    }

    /// For all known validator keypairs, update any known duties from the beacon node.
    fn check_for_duties(&mut self) {
        let cloned_manager = self.duties_manager.clone();
        let cloned_log = self.log.clone();
        let current_epoch = self.current_slot.epoch(self.spec.slots_per_epoch);
        // spawn a new thread separate to the runtime
        // TODO: Handle thread termination/timeout
        std::thread::spawn(move || {
            // the return value is a future which returns ready.
            // built to be compatible with the tokio runtime.
            let _empty = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone());
        });
    }

    /// If there are any duties to process, spawn a separate thread and perform required actions.
    fn process_duties(&mut self) {
        if let Some(work) = self.duties_manager.get_current_work(self.current_slot) {
            for (signer_index, work_type) in work {
                if work_type.produce_block {
                    // spawns a thread to produce a beacon block
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let slot = self.current_slot.clone();
                    let spec = self.spec.clone();
                    let beacon_node = self.beacon_block_client.clone();
                    let log = self.log.clone();
                    std::thread::spawn(move || {
                        info!(log, "Producing a block"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut block_producer = BlockProducer {
                            fork,
                            slot,
                            spec,
                            beacon_node,
                            signer,
                        };
                        block_producer.handle_produce_block(log);
                    });

                    // TODO: Produce a beacon block in a new thread
                }
                if work_type.attestation_duty.is_some() {
                    // available AttestationDuty info
                    /*
                    let attestation_duty =
                        work_type.attestation_duty.expect("Cannot be None");
                    let attester_grpc_client = Arc::new(AttestationGrpcClient::new(
                        service.attester_client.clone(),
                    ));
                    let signer = Arc::new(AttesterLocalSigner::new(keypair.clone()));
                    let attester = Attester::new(attester_grpc_client, signer);
                    let mut attester_service = AttesterService {
                        attester,
                        poll_interval_millis: POLL_INTERVAL_MILLIS,
                        log: log.clone(),
                    };
                    attester_service.run();
                    */
                }
            }
        }
    }
}
<commit_msg>Adds attestation producer to the validation client<commit_after>/// The Validator Client service.
///
/// Connects to a beacon node and negotiates the correct chain id.
///
/// Once connected, the service loads known validators keypairs from disk. Every slot,
/// the service pings the beacon node, asking for new duties for each of the validators.
///
/// When a validator needs to either produce a block or sign an attestation, it requests the
/// data from the beacon node and performs the signing before publishing the block to the beacon
/// node.
use crate::attestation_producer::AttestationProducer;
use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer};
use crate::config::Config as ValidatorConfig;
use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::error::ErrorKind;
use crate::signer::Signer;
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::test_utils::generate_deterministic_keypairs;
use types::{ChainSpec, Epoch, Fork, Slot};

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
//TODO: Generalize the BeaconNode types to use testing
pub struct Service<B: BeaconNodeDuties + 'static, S: Signer + 'static> {
    /// The node's current fork version we are processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// The chain specification for this clients instance.
    spec: Arc<ChainSpec>,
    /// The duties manager which maintains the state of when to perform actions.
    duties_manager: Arc<DutiesManager<B, S>>,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockGrpcClient>,
    /// The attester GRPC client.
    attestation_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl<B: BeaconNodeDuties + 'static, S: Signer + 'static> Service<B, S> {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Service<ValidatorServiceClient, Keypair>> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            BeaconNodeServiceClient::new(ch)
        };

        // retrieve node information and validate the beacon node
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    // verify the node's genesis time
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    // verify the node's chain id
                    if config.spec.chain_id != info.chain_id as u8 {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", config.spec.chain_id, info.chain_id).into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
            // a wrapper around the service client to implement the beacon block node trait
            Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attestation_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock =
            SystemTimeSlotClock::new(genesis_slot, genesis_time, config.spec.seconds_per_slot)
                .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        /* Generate the duties manager */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = Arc::new(generate_deterministic_keypairs(8));

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let duties_manager = Arc::new(DutiesManager {
            duties_map,
            // these are abstract objects capable of signing
            signers: keypairs,
            beacon_node: validator_client,
        });

        let spec = Arc::new(config.spec);

        Ok(Service {
            fork,
            slot_clock,
            current_slot,
            spec,
            duties_manager,
            beacon_block_client,
            attestation_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    // TODO: Improve handling of generic BeaconNode types, to stub grpcClient
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let mut service =
            Service::<ValidatorServiceClient, Keypair>::initialize_service(config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .map_err(|e| format!("System clock error: {:?}", e))?
            .expect("Cannot start before genesis");

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(service.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(Instant::now() + duration_to_next_slot, slot_duration)
        };

        /* kick off the core service */
        runtime.block_on(
            interval
                .for_each(move |_| {
                    // if a non-fatal error occurs, proceed to the next slot.
                    let _ignore_error = service.per_slot_execution();
                    // completed a slot process
                    Ok(())
                })
                .map_err(|e| format!("Service thread failed: {:?}", e)),
        )?;
        // validator client exited
        Ok(())
    }

    /// The execution logic that runs every slot.
    // Errors are logged to output, and core execution continues unless fatal errors occur.
    fn per_slot_execution(&mut self) -> error_chain::Result<()> {
        /* get the new current slot and epoch */
        self.update_current_slot()?;

        /* check for new duties */
        self.check_for_duties();

        /* process any required duties for validators */
        self.process_duties();

        Ok(())
    }

    /// Updates the known current slot and epoch.
    fn update_current_slot(&mut self) -> error_chain::Result<()> {
        let current_slot = match self.slot_clock.present_slot() {
            Err(e) => {
                error!(self.log, "SystemTimeError {:?}", e);
                return Err("Could not read system time".into());
            }
            Ok(slot) => slot.expect("Genesis is in the future"),
        };

        let current_epoch = current_slot.epoch(self.spec.slots_per_epoch);

        // this is a fatal error. If the slot clock repeats, there is something wrong with
        // the timer, terminate immediately.
        assert!(
            current_slot > self.current_slot,
            "The Timer should poll a new slot"
        );
        self.current_slot = current_slot;
        info!(self.log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64());
        Ok(())
    }

    /// For all known validator keypairs, update any known duties from the beacon node.
    fn check_for_duties(&mut self) {
        let cloned_manager = self.duties_manager.clone();
        let cloned_log = self.log.clone();
        let current_epoch = self.current_slot.epoch(self.spec.slots_per_epoch);
        // spawn a new thread separate to the runtime
        // TODO: Handle thread termination/timeout
        std::thread::spawn(move || {
            // the return value is a future which returns ready.
            // built to be compatible with the tokio runtime.
            let _empty = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone());
        });
    }

    /// If there are any duties to process, spawn a separate thread and perform required actions.
    fn process_duties(&mut self) {
        if let Some(work) = self.duties_manager.get_current_work(self.current_slot) {
            for (signer_index, work_type) in work {
                if work_type.produce_block {
                    // we need to produce a block
                    // spawns a thread to produce a beacon block
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let slot = self.current_slot.clone();
                    let spec = self.spec.clone();
                    let beacon_node = self.beacon_block_client.clone();
                    let log = self.log.clone();
                    std::thread::spawn(move || {
                        info!(log, "Producing a block"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut block_producer = BlockProducer {
                            fork,
                            slot,
                            spec,
                            beacon_node,
                            signer,
                        };
                        block_producer.handle_produce_block(log);
                    });
                }
                if work_type.attestation_duty.is_some() {
                    // we need to produce an attestation
                    // spawns a thread to produce and sign an attestation
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let spec = self.spec.clone();
                    let beacon_node = self.attestation_client.clone();
                    let log = self.log.clone();
                    std::thread::spawn(move || {
                        info!(log, "Producing an attestation"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut attestation_producer = AttestationProducer {
                            fork,
                            duty: work_type.attestation_duty.expect("Should never be none"),
                            spec,
                            beacon_node,
                            signer,
                        };
                        attestation_producer.handle_produce_attestation(log);
                    });
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Generated messages reflection support.

use std::collections::HashMap;
use std::fmt;
use std::marker;

use crate::descriptor::FileDescriptorProto;
use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::file::index::FileDescriptorCommon;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::GeneratedOneofDescriptorData;

/// Sized to dynamic reflection operations.
pub(crate) trait MessageFactory: Send + Sync + 'static {
    fn new_instance(&self) -> Box<dyn MessageDyn>;
    fn default_instance(&self) -> &dyn MessageDyn;
    fn clone(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn>;
    fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool;
}

impl<'a> fmt::Debug for &'a dyn MessageFactory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MessageFactory").finish()
    }
}

/// The only message factory implementation.
pub(crate) struct MessageFactoryImpl<M>(pub marker::PhantomData<M>);

impl<M> MessageFactory for MessageFactoryImpl<M>
where
    M: MessageFull,
{
    fn new_instance(&self) -> Box<dyn MessageDyn> {
        let m: M = Default::default();
        Box::new(m)
    }

    fn default_instance(&self) -> &dyn MessageDyn {
        M::default_instance() as &dyn MessageDyn
    }

    fn clone(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn> {
        let m: &M = message.downcast_ref().expect("wrong message type");
        Box::new(m.clone())
    }

    fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool {
        let a: &M = a.downcast_ref().expect("wrong message type");
        let b: &M = b.downcast_ref().expect("wrong message type");
        a == b
    }
}

#[doc(hidden)]
pub struct GeneratedMessageDescriptorData {
    pub(crate) protobuf_name_to_package: &'static str,
    pub(crate) fields: Vec<FieldAccessor>,
    pub(crate) factory: &'static dyn MessageFactory,
}

impl GeneratedMessageDescriptorData {
    /// Construct a new message descriptor.
    ///
    /// This operation is called from generated code and rarely
    /// need to be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new<M: MessageFull>(
        protobuf_name_to_package: &'static str,
        fields: Vec<FieldAccessor>,
    ) -> GeneratedMessageDescriptorData {
        let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
        GeneratedMessageDescriptorData {
            protobuf_name_to_package,
            fields,
            factory,
        }
    }

    /// Construct a new message descriptor.
    ///
    /// This operation is called from generated code and rarely
    /// need to be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new_2<M: MessageFull>(
        protobuf_name_to_package: &'static str,
        fields: Vec<FieldAccessor>,
        oneofs: Vec<GeneratedOneofDescriptorData>,
    ) -> GeneratedMessageDescriptorData {
        let _ = oneofs; // TODO: use
        let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
        GeneratedMessageDescriptorData {
            protobuf_name_to_package,
            fields,
            factory,
        }
    }
}

#[derive(Debug)]
pub(crate) struct NonMapMessageDescriptor {
    pub(crate) factory: &'static dyn MessageFactory,

    pub(crate) fields: Vec<FieldAccessor>,
}

#[derive(Debug)]
pub(crate) struct GeneratedMessageDescriptor {
    pub(crate) non_map: Option<NonMapMessageDescriptor>,
}

impl GeneratedMessageDescriptor {
    pub(crate) fn new_map_entry() -> GeneratedMessageDescriptor {
        GeneratedMessageDescriptor { non_map: None }
    }

    pub(crate) fn new(
        data: GeneratedMessageDescriptorData,
        file_descriptor_proto: &'static FileDescriptorProto,
        _file_index: &FileDescriptorCommon,
    ) -> crate::Result<GeneratedMessageDescriptor> {
        let GeneratedMessageDescriptorData {
            protobuf_name_to_package,
            fields,
            factory,
        } = data;

        let (_path_to_package, proto) =
            match find_message_or_enum(file_descriptor_proto, protobuf_name_to_package) {
                Some((path_to_package, MessageOrEnum::Message(m))) => (path_to_package, m),
                Some((_, MessageOrEnum::Enum(_))) => panic!("not a message"),
                None => panic!("not found"),
            };

        let mut field_proto_by_name = HashMap::new();
        for field_proto in &proto.field {
            field_proto_by_name.insert(field_proto.name(), field_proto);
        }

        Ok(GeneratedMessageDescriptor {
            non_map: Some(NonMapMessageDescriptor { factory, fields }),
        })
    }

    pub(crate) fn non_map(&self) -> &NonMapMessageDescriptor {
        match &self.non_map {
            Some(non_map) => non_map,
            None => panic!("map message"),
        }
    }
}
<commit_msg>Dead code<commit_after>//! Generated messages reflection support.

use std::collections::HashMap;
use std::fmt;
use std::marker;

use crate::descriptor::FileDescriptorProto;
use crate::message_dyn::MessageDyn;
use crate::message_full::MessageFull;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::file::index::FileDescriptorCommon;
use crate::reflect::find_message_or_enum::find_message_or_enum;
use crate::reflect::find_message_or_enum::MessageOrEnum;
use crate::reflect::GeneratedOneofDescriptorData;

/// Sized to dynamic reflection operations.
pub(crate) trait MessageFactory: Send + Sync + 'static {
    fn new_instance(&self) -> Box<dyn MessageDyn>;
    fn default_instance(&self) -> &dyn MessageDyn;
    fn clone(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn>;
    fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool;
}

impl<'a> fmt::Debug for &'a dyn MessageFactory {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("MessageFactory").finish()
    }
}

/// The only message factory implementation.
pub(crate) struct MessageFactoryImpl<M>(pub marker::PhantomData<M>);

impl<M> MessageFactory for MessageFactoryImpl<M>
where
    M: MessageFull,
{
    fn new_instance(&self) -> Box<dyn MessageDyn> {
        let m: M = Default::default();
        Box::new(m)
    }

    fn default_instance(&self) -> &dyn MessageDyn {
        M::default_instance() as &dyn MessageDyn
    }

    fn clone(&self, message: &dyn MessageDyn) -> Box<dyn MessageDyn> {
        let m: &M = message.downcast_ref().expect("wrong message type");
        Box::new(m.clone())
    }

    fn eq(&self, a: &dyn MessageDyn, b: &dyn MessageDyn) -> bool {
        let a: &M = a.downcast_ref().expect("wrong message type");
        let b: &M = b.downcast_ref().expect("wrong message type");
        a == b
    }
}

#[doc(hidden)]
pub struct GeneratedMessageDescriptorData {
    pub(crate) protobuf_name_to_package: &'static str,
    pub(crate) fields: Vec<FieldAccessor>,
    pub(crate) factory: &'static dyn MessageFactory,
}

impl GeneratedMessageDescriptorData {
    /// Construct a new message descriptor.
    ///
    /// This operation is called from generated code and rarely
    /// need to be called directly.
    ///
    /// This function is not a part of public API.
    #[doc(hidden)]
    pub fn new_2<M: MessageFull>(
        protobuf_name_to_package: &'static str,
        fields: Vec<FieldAccessor>,
        oneofs: Vec<GeneratedOneofDescriptorData>,
    ) -> GeneratedMessageDescriptorData {
        let _ = oneofs; // TODO: use
        let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
        GeneratedMessageDescriptorData {
            protobuf_name_to_package,
            fields,
            factory,
        }
    }
}

#[derive(Debug)]
pub(crate) struct NonMapMessageDescriptor {
    pub(crate) factory: &'static dyn MessageFactory,

    pub(crate) fields: Vec<FieldAccessor>,
}

#[derive(Debug)]
pub(crate) struct GeneratedMessageDescriptor {
    pub(crate) non_map: Option<NonMapMessageDescriptor>,
}

impl GeneratedMessageDescriptor {
    pub(crate) fn new_map_entry() -> GeneratedMessageDescriptor {
        GeneratedMessageDescriptor { non_map: None }
    }

    pub(crate) fn new(
        data: GeneratedMessageDescriptorData,
        file_descriptor_proto: &'static FileDescriptorProto,
        _file_index: &FileDescriptorCommon,
    ) -> crate::Result<GeneratedMessageDescriptor> {
        let GeneratedMessageDescriptorData {
            protobuf_name_to_package,
            fields,
            factory,
        } = data;

        let (_path_to_package, proto) =
            match find_message_or_enum(file_descriptor_proto, protobuf_name_to_package) {
                Some((path_to_package, MessageOrEnum::Message(m))) => (path_to_package, m),
                Some((_, MessageOrEnum::Enum(_))) => panic!("not a message"),
                None => panic!("not found"),
            };

        let mut field_proto_by_name = HashMap::new();
        for field_proto in &proto.field {
            field_proto_by_name.insert(field_proto.name(), field_proto);
        }

        Ok(GeneratedMessageDescriptor {
            non_map: Some(NonMapMessageDescriptor { factory, fields }),
        })
    }

    pub(crate) fn non_map(&self) -> &NonMapMessageDescriptor {
        match &self.non_map {
            Some(non_map) => non_map,
            None => panic!("map message"),
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagstore::hook::Hook;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::accessor::HookDataAccessor as HDA;
use libimagstore::hook::accessor::HookDataAccessorProvider;
use libimagstore::hook::accessor::NonMutableHookDataAccessor;
use libimagstore::hook::result::HookResult;
use libimagstore::store::FileLockEntry;
use libimagentrylink::internal::InternalLinker;

mod error {
    generate_error_imports!();
    generate_error_types!(NoLinksLeftCheckerHookError, NoLinksLeftCheckerHookErrorKind,
        ReadInternalLinksError  => "Error while reading internal links of entry",
        LinksLeft               => "The entry has links and therefor cannot be deleted."
    );
}
use self::error::NoLinksLeftCheckerHookErrorKind as NLLCHEK;

#[derive(Debug, Clone)]
pub struct DenyDeletionOfLinkedEntriesHook {
    abort: bool
}

impl DenyDeletionOfLinkedEntriesHook {

    pub fn new() -> DenyDeletionOfLinkedEntriesHook {
        DenyDeletionOfLinkedEntriesHook {
            abort: true // by default, this hook aborts actions
        }
    }

}

impl Hook for DenyDeletionOfLinkedEntriesHook {

    fn name(&self) -> &'static str {
        "stdhook_linked_entries_cannot_be_deleted"
    }

    fn set_config(&mut self, v: &Value) {
        self.abort = match v.lookup("aborting") {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, 'aborting' must be a Boolean (true|false).");
                warn!("Assuming 'true' now.");
                true
            },
            None => {
                warn!("No key 'aborting' - Assuming 'true'");
                true
            },
        };
    }

}

impl HookDataAccessorProvider for DenyDeletionOfLinkedEntriesHook {

    fn accessor(&self) -> HDA {
        HDA::NonMutableAccess(self)
    }

}

impl NonMutableHookDataAccessor for DenyDeletionOfLinkedEntriesHook {

    fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use self::error::MapErrInto;

        debug!("[NO LINKS LEFT CHECKER HOOK] {:?}", fle.get_location());

        let n = try!(fle
            .get_internal_links()
            .map(|i| i.count())
            .map_err_into(NLLCHEK::ReadInternalLinksError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));

        if n > 0 {
            Err(NLLCHEK::LinksLeft.into_error())
                .map_err(Box::new)
                .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
        } else {
            Ok(())
        }
    }

}

<commit_msg>Adapt DenyDeletionOfLinkedEntriesHook to toml 0.4<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagstore::hook::Hook;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::accessor::HookDataAccessor as HDA;
use libimagstore::hook::accessor::HookDataAccessorProvider;
use libimagstore::hook::accessor::NonMutableHookDataAccessor;
use libimagstore::hook::result::HookResult;
use libimagstore::store::FileLockEntry;
use libimagstore::toml_ext::TomlValueExt;
use libimagentrylink::internal::InternalLinker;
use libimagerror::trace::trace_error;

mod error {
    generate_error_imports!();
    generate_error_types!(NoLinksLeftCheckerHookError, NoLinksLeftCheckerHookErrorKind,
        ReadInternalLinksError  => "Error while reading internal links of entry",
        LinksLeft               => "The entry has links and therefor cannot be deleted."
    );
}
use self::error::NoLinksLeftCheckerHookErrorKind as NLLCHEK;

#[derive(Debug, Clone)]
pub struct DenyDeletionOfLinkedEntriesHook {
    abort: bool
}

impl DenyDeletionOfLinkedEntriesHook {

    pub fn new() -> DenyDeletionOfLinkedEntriesHook {
        DenyDeletionOfLinkedEntriesHook {
            abort: true // by default, this hook aborts actions
        }
    }

}

impl Hook for DenyDeletionOfLinkedEntriesHook {

    fn name(&self) -> &'static str {
        "stdhook_linked_entries_cannot_be_deleted"
    }

    fn set_config(&mut self, v: &Value) {
        self.abort = match v.read("aborting") {
            Ok(Some(Value::Boolean(b))) => b,
            Ok(Some(_)) => {
                warn!("Configuration error, 'aborting' must be a Boolean (true|false).");
                warn!("Assuming 'true' now.");
                true
            },
            Ok(None) => {
                warn!("No key 'aborting' - Assuming 'true'");
                true
            },
            Err(e) => {
                error!("Error parsing TOML:");
                trace_error(&e);
                false
            },
        };
    }

}

impl HookDataAccessorProvider for DenyDeletionOfLinkedEntriesHook {

    fn accessor(&self) -> HDA {
        HDA::NonMutableAccess(self)
    }

}

impl NonMutableHookDataAccessor for DenyDeletionOfLinkedEntriesHook {

    fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use self::error::MapErrInto;

        debug!("[NO LINKS LEFT CHECKER HOOK] {:?}", fle.get_location());

        let n = try!(fle
            .get_internal_links()
            .map(|i| i.count())
            .map_err_into(NLLCHEK::ReadInternalLinksError)
            .map_err(Box::new)
            .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e)));

        if n > 0 {
            Err(NLLCHEK::LinksLeft.into_error())
                .map_err(Box::new)
                .map_err(|e| HEK::HookExecutionError.into_error_with_cause(e))
        } else {
            Ok(())
        }
    }

}

<|endoftext|>


<commit_before>use layers::Layer;
use geom::size::Size2D;

struct Scene {
    mut root: Layer,
    mut size: Size2D<f32>
}

fn Scene(root: Layer, size: Size2D<f32>) -> Scene {
    Scene {
        root : root,
        size : size
    }
}

<commit_msg>Update for language changes<commit_after>use layers::Layer;
use geom::size::Size2D;

pub struct Scene {
    mut root: Layer,
    mut size: Size2D<f32>
}

pub fn Scene(root: Layer, size: Size2D<f32>) -> Scene {
    Scene {
        root : root,
        size : size
    }
}

<|endoftext|>


<commit_before>use super::{Error, Invalid, Outcome};

/// Check that an attestation is valid to be included in some block.
pub fn validate_attestation_for_block(
    attestation_slot: u64,
    block_slot: u64,
    parent_block_slot: u64,
    min_attestation_inclusion_delay: u64,
    epoch_length: u64,
) -> Result<Outcome, Error> {
    /*
     * There is a delay before an attestation may be included in a block, quantified by
     * `slots` and defined as `min_attestation_inclusion_delay`.
     *
     * So, an attestation must be at least `min_attestation_inclusion_delay` slots "older" than the
     * block it is contained in.
     */
    verify_or!(
        // TODO: this differs from the spec as it does not handle underflows correctly.
        // https://github.com/sigp/lighthouse/issues/95
        attestation_slot < block_slot.saturating_sub(min_attestation_inclusion_delay - 1),
        reject!(Invalid::AttestationTooRecent)
    );

    /*
     * A block may not include attestations reference slots more than an epoch length + 1 prior to
     * the block slot.
     */
    verify_or!(
        attestation_slot >= parent_block_slot.saturating_sub(epoch_length + 1),
        reject!(Invalid::AttestationTooOld)
    );

    accept!()
}

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

    #[test]
    fn test_inclusion_delay_minimal() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - min_attestation_inclusion_delay;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_delay_maximal() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - epoch_length;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_delay_insufficient() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - (min_attestation_inclusion_delay - 1);

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }

    #[test]
    fn test_inclusion_delay_first_possible_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay;
        let attestation_slot = 0;
        let parent_block_slot = block_slot - 1;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_delay_saturation_non_zero_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay - 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = 0;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }

    #[test]
    fn test_inclusion_delay_saturation_zero_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay - 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = 0;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }
}
<commit_msg>Add more attestation validation tests<commit_after>use super::{Error, Invalid, Outcome};

/// Check that an attestation is valid to be included in some block.
pub fn validate_attestation_for_block(
    attestation_slot: u64,
    block_slot: u64,
    parent_block_slot: u64,
    min_attestation_inclusion_delay: u64,
    epoch_length: u64,
) -> Result<Outcome, Error> {
    /*
     * There is a delay before an attestation may be included in a block, quantified by
     * `slots` and defined as `min_attestation_inclusion_delay`.
     *
     * So, an attestation must be at least `min_attestation_inclusion_delay` slots "older" than the
     * block it is contained in.
     */
    verify_or!(
        // TODO: this differs from the spec as it does not handle underflows correctly.
        // https://github.com/sigp/lighthouse/issues/95
        attestation_slot < block_slot.saturating_sub(min_attestation_inclusion_delay - 1),
        reject!(Invalid::AttestationTooRecent)
    );

    /*
     * A block may not include attestations reference slots more than an epoch length + 1 prior to
     * the block slot.
     */
    verify_or!(
        attestation_slot >= parent_block_slot.saturating_sub(epoch_length + 1),
        reject!(Invalid::AttestationTooOld)
    );

    accept!()
}

#[cfg(test)]
mod tests {
    use super::*;
    /*
     * Invalid::AttestationTooOld tests.
     */

    #[test]
    fn test_inclusion_too_old_minimal() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = block_slot - min_attestation_inclusion_delay;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_old_maximal() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = block_slot - epoch_length + 1;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_old_saturating_non_zero_attestation_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = epoch_length + 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = block_slot - min_attestation_inclusion_delay;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_old_saturating_zero_attestation_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = epoch_length + 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = 0;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_old() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = epoch_length * 2;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = parent_block_slot - (epoch_length + 2);

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooOld)));
    }

    /*
     * Invalid::AttestationTooRecent tests.
     */

    #[test]
    fn test_inclusion_too_recent_minimal() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - min_attestation_inclusion_delay;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_recent_maximal() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - epoch_length;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_recent_insufficient() {
        let parent_block_slot = 99;
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = 100;
        let attestation_slot = block_slot - (min_attestation_inclusion_delay - 1);

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }

    #[test]
    fn test_inclusion_too_recent_first_possible_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay;
        let attestation_slot = 0;
        let parent_block_slot = block_slot - 1;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Valid));
    }

    #[test]
    fn test_inclusion_too_recent_saturation_non_zero_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay - 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = 0;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }

    #[test]
    fn test_inclusion_too_recent_saturation_zero_slot() {
        let min_attestation_inclusion_delay = 10;
        let epoch_length = 20;
        let block_slot = min_attestation_inclusion_delay - 1;
        let parent_block_slot = block_slot - 1;
        let attestation_slot = 0;

        let outcome = validate_attestation_for_block(
            attestation_slot,
            block_slot,
            parent_block_slot,
            min_attestation_inclusion_delay,
            epoch_length,
        );
        assert_eq!(outcome, Ok(Outcome::Invalid(Invalid::AttestationTooRecent)));
    }
}
<|endoftext|>


<commit_before>use crate::local_network::LocalNetwork;
use std::time::Duration;
use types::{Epoch, EthSpec, Slot, Unsigned};

/// Checks that all of the validators have on-boarded by the start of the second eth1 voting
/// period.
pub async fn verify_initial_validator_count<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
    initial_validator_count: usize,
) -> Result<(), String> {
    slot_delay(Slot::new(1), slot_duration).await;
    verify_validator_count(network, initial_validator_count).await?;
    Ok(())
}

/// Checks that all of the validators have on-boarded by the start of the second eth1 voting
/// period.
pub async fn verify_validator_onboarding<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
    expected_validator_count: usize,
) -> Result<(), String> {
    slot_delay(
        Slot::new(E::SlotsPerEth1VotingPeriod::to_u64()),
        slot_duration,
    )
    .await;
    verify_validator_count(network, expected_validator_count).await?;
    Ok(())
}

/// Checks that the chain has made the first possible finalization.
///
/// Intended to be run as soon as chain starts.
pub async fn verify_first_finalization<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
) -> Result<(), String> {
    epoch_delay(Epoch::new(4), slot_duration, E::slots_per_epoch()).await;
    verify_all_finalized_at(network, Epoch::new(2)).await?;
    Ok(())
}

/// Delays for `epochs`, plus half a slot extra.
pub async fn epoch_delay(epochs: Epoch, slot_duration: Duration, slots_per_epoch: u64) {
    let duration = slot_duration * (epochs.as_u64() * slots_per_epoch) as u32 + slot_duration / 2;
    tokio::time::delay_for(duration).await
}

/// Delays for `slots`, plus half a slot extra.
async fn slot_delay(slots: Slot, slot_duration: Duration) {
    let duration = slot_duration * slots.as_u64() as u32 + slot_duration / 2;
    tokio::time::delay_for(duration).await;
}

/// Verifies that all beacon nodes in the given network have a head state that has a finalized
/// epoch of `epoch`.
pub async fn verify_all_finalized_at<E: EthSpec>(
    network: LocalNetwork<E>,
    epoch: Epoch,
) -> Result<(), String> {
    let epochs = {
        let mut epochs = Vec::new();
        for remote_node in network.remote_nodes()? {
            epochs.push(
                remote_node
                    .http
                    .beacon()
                    .get_head()
                    .await
                    .map(|head| head.finalized_slot.epoch(E::slots_per_epoch()))
                    .map_err(|e| format!("Get head via http failed: {:?}", e))?,
            );
        }
        epochs
    };

    if epochs.iter().any(|node_epoch| *node_epoch != epoch) {
        Err(format!(
            "Nodes are not finalized at epoch {}. Finalized epochs: {:?}",
            epoch, epochs
        ))
    } else {
        Ok(())
    }
}

/// Verifies that all beacon nodes in the given `network` have a head state that contains
/// `expected_count` validators.
async fn verify_validator_count<E: EthSpec>(
    network: LocalNetwork<E>,
    expected_count: usize,
) -> Result<(), String> {
    let validator_counts = {
        let mut validator_counts = Vec::new();
        for remote_node in network.remote_nodes()? {
            let beacon = remote_node.http.beacon();

            let head = beacon
                .get_head()
                .await
                .map_err(|e| format!("Get head via http failed: {:?}", e))?;

            let vc = beacon
                .get_state_by_root(head.state_root)
                .await
                .map(|(state, _root)| state)
                .map_err(|e| format!("Get state root via http failed: {:?}", e))?
                .validators
                .len();
            validator_counts.push(vc);
        }
        validator_counts
    };

    if validator_counts
        .iter()
        .any(|count| *count != expected_count)
    {
        Err(format!(
            "Nodes do not all have {} validators in their state. Validator counts: {:?}",
            expected_count, validator_counts
        ))
    } else {
        Ok(())
    }
}

/// Verifies that there's been a block produced at every slot up to and including `slot`.
pub async fn verify_full_block_production_up_to<E: EthSpec>(
    network: LocalNetwork<E>,
    slot: Slot,
    slot_duration: Duration,
) -> Result<(), String> {
    slot_delay(slot, slot_duration).await;
    let beacon_nodes = network.beacon_nodes.read();
    let beacon_chain = beacon_nodes[0].client.beacon_chain().unwrap();
    let chain_dump = beacon_chain.chain_dump().unwrap();
    if chain_dump.len() != slot.as_usize() + 1 {
        return Err(format!(
            "There wasn't a block produced at every slot, got: {}, expected: {}",
            chain_dump.len(),
            slot.as_usize() + 1
        ));
    }
    Ok(())
}
<commit_msg>Fix block check in simulator (#1398)<commit_after>use crate::local_network::LocalNetwork;
use std::time::Duration;
use types::{Epoch, EthSpec, Slot, Unsigned};

/// Checks that all of the validators have on-boarded by the start of the second eth1 voting
/// period.
pub async fn verify_initial_validator_count<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
    initial_validator_count: usize,
) -> Result<(), String> {
    slot_delay(Slot::new(1), slot_duration).await;
    verify_validator_count(network, initial_validator_count).await?;
    Ok(())
}

/// Checks that all of the validators have on-boarded by the start of the second eth1 voting
/// period.
pub async fn verify_validator_onboarding<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
    expected_validator_count: usize,
) -> Result<(), String> {
    slot_delay(
        Slot::new(E::SlotsPerEth1VotingPeriod::to_u64()),
        slot_duration,
    )
    .await;
    verify_validator_count(network, expected_validator_count).await?;
    Ok(())
}

/// Checks that the chain has made the first possible finalization.
///
/// Intended to be run as soon as chain starts.
pub async fn verify_first_finalization<E: EthSpec>(
    network: LocalNetwork<E>,
    slot_duration: Duration,
) -> Result<(), String> {
    epoch_delay(Epoch::new(4), slot_duration, E::slots_per_epoch()).await;
    verify_all_finalized_at(network, Epoch::new(2)).await?;
    Ok(())
}

/// Delays for `epochs`, plus half a slot extra.
pub async fn epoch_delay(epochs: Epoch, slot_duration: Duration, slots_per_epoch: u64) {
    let duration = slot_duration * (epochs.as_u64() * slots_per_epoch) as u32 + slot_duration / 2;
    tokio::time::delay_for(duration).await
}

/// Delays for `slots`, plus half a slot extra.
async fn slot_delay(slots: Slot, slot_duration: Duration) {
    let duration = slot_duration * slots.as_u64() as u32 + slot_duration / 2;
    tokio::time::delay_for(duration).await;
}

/// Verifies that all beacon nodes in the given network have a head state that has a finalized
/// epoch of `epoch`.
pub async fn verify_all_finalized_at<E: EthSpec>(
    network: LocalNetwork<E>,
    epoch: Epoch,
) -> Result<(), String> {
    let epochs = {
        let mut epochs = Vec::new();
        for remote_node in network.remote_nodes()? {
            epochs.push(
                remote_node
                    .http
                    .beacon()
                    .get_head()
                    .await
                    .map(|head| head.finalized_slot.epoch(E::slots_per_epoch()))
                    .map_err(|e| format!("Get head via http failed: {:?}", e))?,
            );
        }
        epochs
    };

    if epochs.iter().any(|node_epoch| *node_epoch != epoch) {
        Err(format!(
            "Nodes are not finalized at epoch {}. Finalized epochs: {:?}",
            epoch, epochs
        ))
    } else {
        Ok(())
    }
}

/// Verifies that all beacon nodes in the given `network` have a head state that contains
/// `expected_count` validators.
async fn verify_validator_count<E: EthSpec>(
    network: LocalNetwork<E>,
    expected_count: usize,
) -> Result<(), String> {
    let validator_counts = {
        let mut validator_counts = Vec::new();
        for remote_node in network.remote_nodes()? {
            let beacon = remote_node.http.beacon();

            let head = beacon
                .get_head()
                .await
                .map_err(|e| format!("Get head via http failed: {:?}", e))?;

            let vc = beacon
                .get_state_by_root(head.state_root)
                .await
                .map(|(state, _root)| state)
                .map_err(|e| format!("Get state root via http failed: {:?}", e))?
                .validators
                .len();
            validator_counts.push(vc);
        }
        validator_counts
    };

    if validator_counts
        .iter()
        .any(|count| *count != expected_count)
    {
        Err(format!(
            "Nodes do not all have {} validators in their state. Validator counts: {:?}",
            expected_count, validator_counts
        ))
    } else {
        Ok(())
    }
}

/// Verifies that there's been a block produced at every slot up to and including `slot`.
pub async fn verify_full_block_production_up_to<E: EthSpec>(
    network: LocalNetwork<E>,
    slot: Slot,
    slot_duration: Duration,
) -> Result<(), String> {
    slot_delay(slot, slot_duration).await;
    let beacon_nodes = network.beacon_nodes.read();
    let beacon_chain = beacon_nodes[0].client.beacon_chain().unwrap();
    let num_blocks = beacon_chain
        .chain_dump()
        .unwrap()
        .iter()
        .take_while(|s| s.beacon_block.slot() <= slot)
        .count();
    if num_blocks != slot.as_usize() + 1 {
        return Err(format!(
            "There wasn't a block produced at every slot, got: {}, expected: {}",
            num_blocks,
            slot.as_usize() + 1
        ));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use libtww::game::controller;
use libtww::system;

use visible as debug_menu_visible;

pub const DPAD_LEFT: Button = Button(0);
pub const DPAD_RIGHT: Button = Button(1);
pub const DPAD_DOWN: Button = Button(2);
pub const DPAD_UP: Button = Button(3);
pub const Z: Button = Button(4);
pub const R: Button = Button(5);
pub const L: Button = Button(6);
pub const A: Button = Button(7);
pub const B: Button = Button(8);
pub const X: Button = Button(9);
pub const Y: Button = Button(10);
pub const START: Button = Button(11);

const REPEAT_TIME: u32 = 3;
const REPEAT_DELAY: u32 = 5;

pub struct Button(usize);

impl Button {
    pub fn is_pressed(&self) -> bool {
        let delta = system::get_frame_count() - unsafe { button_states[self.0].pressed_frame };
        let just_clicked = delta == 0;
        let held_down_long_enough = delta > REPEAT_DELAY;
        let is_repeat_frame = held_down_long_enough && delta % REPEAT_TIME < REPEAT_TIME - 1;

        self.is_down() && (just_clicked || is_repeat_frame)
    }

    pub fn is_down(&self) -> bool {
        unsafe { button_states[self.0].is_down }
    }
}

static mut button_states: [ButtonState; 12] = [
    ButtonState::new(controller::DPAD_LEFT),
    ButtonState::new(controller::DPAD_RIGHT),
    ButtonState::new(controller::DPAD_DOWN),
    ButtonState::new(controller::DPAD_UP),
    ButtonState::new(controller::Z),
    ButtonState::new(controller::R),
    ButtonState::new(controller::L),
    ButtonState::new(controller::A),
    ButtonState::new(controller::B),
    ButtonState::new(controller::X),
    ButtonState::new(controller::Y),
    ButtonState::new(controller::START),
];

struct ButtonState {
    button: u16,
    pressed_frame: u32,
    is_down: bool,
}

impl ButtonState {
    const fn new(button: u16) -> Self {
        ButtonState {
            button: button,
            pressed_frame: 0xFFFFFFFF,
            is_down: false,
        }
    }
}

static mut buttons_pressed: u16 = 0;
static mut buttons_down: u16 = 0;
static mut buttons_down_last_frame: u16 = 0;

#[no_mangle]
pub extern "C" fn read_controller() -> u32 {
    unsafe {
        buttons_down_last_frame = buttons_down;
        buttons_down = system::memory::read(0x803E0CF8);
        buttons_pressed = buttons_down & (0xFFFF ^ buttons_down_last_frame);

        for state in &mut button_states {
            state.is_down = state.button & buttons_down != 0;
            if state.button & buttons_pressed != 0 {
                state.pressed_frame = system::get_frame_count() + 1;
            }
        }
    }
    if unsafe { debug_menu_visible } {
        controller::set_buttons_down(0x0);
        controller::set_buttons_pressed(0x0);
        system::memory::write::<u16>(0x803E0D42, 0x0);
        system::memory::write::<u16>(0x803E0CF8, 0x0);
    }
    0x80000000
}
<commit_msg>Actually build correctly<commit_after>use libtww::game::gamepad;
use libtww::system;

use visible as debug_menu_visible;

pub const DPAD_LEFT: Button = Button(0);
pub const DPAD_RIGHT: Button = Button(1);
pub const DPAD_DOWN: Button = Button(2);
pub const DPAD_UP: Button = Button(3);
pub const Z: Button = Button(4);
pub const R: Button = Button(5);
pub const L: Button = Button(6);
pub const A: Button = Button(7);
pub const B: Button = Button(8);
pub const X: Button = Button(9);
pub const Y: Button = Button(10);
pub const START: Button = Button(11);

const REPEAT_TIME: u32 = 3;
const REPEAT_DELAY: u32 = 5;

pub struct Button(usize);

impl Button {
    pub fn is_pressed(&self) -> bool {
        let delta = system::get_frame_count() - unsafe { button_states[self.0].pressed_frame };
        let just_clicked = delta == 0;
        let held_down_long_enough = delta > REPEAT_DELAY;
        let is_repeat_frame = held_down_long_enough && delta % REPEAT_TIME < REPEAT_TIME - 1;

        self.is_down() && (just_clicked || is_repeat_frame)
    }

    pub fn is_down(&self) -> bool {
        unsafe { button_states[self.0].is_down }
    }
}

static mut button_states: [ButtonState; 12] = [
    ButtonState::new(gamepad::DPAD_LEFT),
    ButtonState::new(gamepad::DPAD_RIGHT),
    ButtonState::new(gamepad::DPAD_DOWN),
    ButtonState::new(gamepad::DPAD_UP),
    ButtonState::new(gamepad::Z),
    ButtonState::new(gamepad::R),
    ButtonState::new(gamepad::L),
    ButtonState::new(gamepad::A),
    ButtonState::new(gamepad::B),
    ButtonState::new(gamepad::X),
    ButtonState::new(gamepad::Y),
    ButtonState::new(gamepad::START),
];

struct ButtonState {
    button: u16,
    pressed_frame: u32,
    is_down: bool,
}

impl ButtonState {
    const fn new(button: u16) -> Self {
        ButtonState {
            button: button,
            pressed_frame: 0xFFFFFFFF,
            is_down: false,
        }
    }
}

static mut buttons_pressed: u16 = 0;
static mut buttons_down: u16 = 0;
static mut buttons_down_last_frame: u16 = 0;

#[no_mangle]
pub extern "C" fn read_controller() -> u32 {
    unsafe {
        buttons_down_last_frame = buttons_down;
        buttons_down = system::memory::read(0x803E0CF8);
        buttons_pressed = buttons_down & (0xFFFF ^ buttons_down_last_frame);

        for state in &mut button_states {
            state.is_down = state.button & buttons_down != 0;
            if state.button & buttons_pressed != 0 {
                state.pressed_frame = system::get_frame_count() + 1;
            }
        }
    }
    if unsafe { debug_menu_visible } {
        gamepad::set_buttons_down(0x0);
        gamepad::set_buttons_pressed(0x0);
        system::memory::write::<u16>(0x803E0D42, 0x0);
        system::memory::write::<u16>(0x803E0CF8, 0x0);
    }
    0x80000000
}
<|endoftext|>


<commit_before>use crate::actually_private::Private;
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::mem::MaybeUninit;
use core::pin::Pin;
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge1$cxx_string$init"]
    fn string_init(this: &mut MaybeUninit<CxxString>, ptr: *const u8, len: usize);
    #[link_name = "cxxbridge1$cxx_string$destroy"]
    fn string_destroy(this: &mut MaybeUninit<CxxString>);
    #[link_name = "cxxbridge1$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge1$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge1$cxx_string$push"]
    fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
    _pinned: PhantomData<PhantomPinned>,
}

/// Construct a C++ std::string on the Rust stack.
///
/// # Syntax
///
/// In statement position:
///
/// ```
/// # use cxx::let_cxx_string;
/// # let expression = "";
/// let_cxx_string!(var = expression);
/// ```
///
/// The `expression` may have any type that implements `AsRef<[u8]>`. Commonly
/// it will be a string literal, but for example `&[u8]` and `String` would work
/// as well.
///
/// The macro expands to something resembling `let $var: Pin<&mut CxxString> =
/// /*???*/;`. The resulting [`Pin`] can be deref'd to `&CxxString` as needed.
///
/// # Example
///
/// ```
/// use cxx::{let_cxx_string, CxxString};
///
/// fn f(s: &CxxString) {/* ... */}
///
/// fn main() {
///     let_cxx_string!(s = "example");
///     f(&s);
/// }
/// ```
#[macro_export]
macro_rules! let_cxx_string {
    ($var:ident = $value:expr $(,)?) => {
        let mut $var = $crate::private::StackString::new();
        #[allow(unused_mut, unused_unsafe)]
        let mut $var = unsafe { $var.init($value) };
    };
}

impl CxxString {
    /// `CxxString` is not constructible via `new`. Instead, use the
    /// [`let_cxx_string!`] macro.
    pub fn new<T: Private>() -> Self {
        unreachable!()
    }

    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(self: Pin<&mut Self>, s: &str) {
        self.push_bytes(s.as_bytes());
    }

    /// Appends arbitrary bytes onto the end of this C++ string.
    pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) {
        unsafe { string_push(self, bytes.as_ptr(), bytes.len()) }
    }
}

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

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

#[doc(hidden)]
#[repr(C)]
pub struct StackString {
    // Static assertions in cxx.cc validate that this is large enough and
    // aligned enough.
    space: MaybeUninit<[*const (); 8]>,
}

impl StackString {
    pub fn new() -> Self {
        StackString {
            space: MaybeUninit::uninit(),
        }
    }

    pub unsafe fn init(&mut self, value: impl AsRef<[u8]>) -> Pin<&mut CxxString> {
        let value = value.as_ref();
        let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
        string_init(this, value.as_ptr(), value.len());
        Pin::new_unchecked(&mut *this.as_mut_ptr())
    }
}

impl Drop for StackString {
    fn drop(&mut self) {
        unsafe {
            let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
            string_destroy(this);
        }
    }
}
<commit_msg>Move let_cxx_string's $value evaluation outside of unsafe block<commit_after>use crate::actually_private::Private;
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::mem::MaybeUninit;
use core::pin::Pin;
use core::slice;
use core::str::{self, Utf8Error};

extern "C" {
    #[link_name = "cxxbridge1$cxx_string$init"]
    fn string_init(this: &mut MaybeUninit<CxxString>, ptr: *const u8, len: usize);
    #[link_name = "cxxbridge1$cxx_string$destroy"]
    fn string_destroy(this: &mut MaybeUninit<CxxString>);
    #[link_name = "cxxbridge1$cxx_string$data"]
    fn string_data(this: &CxxString) -> *const u8;
    #[link_name = "cxxbridge1$cxx_string$length"]
    fn string_length(this: &CxxString) -> usize;
    #[link_name = "cxxbridge1$cxx_string$push"]
    fn string_push(this: Pin<&mut CxxString>, ptr: *const u8, len: usize);
}

/// Binding to C++ `std::string`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxString` by value. C++'s string
/// requires a move constructor and may hold internal pointers, which is not
/// compatible with Rust's move behavior. Instead in Rust code we will only ever
/// look at a CxxString through a reference or smart pointer, as in `&CxxString`
/// or `UniquePtr<CxxString>`.
#[repr(C)]
pub struct CxxString {
    _private: [u8; 0],
    _pinned: PhantomData<PhantomPinned>,
}

/// Construct a C++ std::string on the Rust stack.
///
/// # Syntax
///
/// In statement position:
///
/// ```
/// # use cxx::let_cxx_string;
/// # let expression = "";
/// let_cxx_string!(var = expression);
/// ```
///
/// The `expression` may have any type that implements `AsRef<[u8]>`. Commonly
/// it will be a string literal, but for example `&[u8]` and `String` would work
/// as well.
///
/// The macro expands to something resembling `let $var: Pin<&mut CxxString> =
/// /*???*/;`. The resulting [`Pin`] can be deref'd to `&CxxString` as needed.
///
/// # Example
///
/// ```
/// use cxx::{let_cxx_string, CxxString};
///
/// fn f(s: &CxxString) {/* ... */}
///
/// fn main() {
///     let_cxx_string!(s = "example");
///     f(&s);
/// }
/// ```
#[macro_export]
macro_rules! let_cxx_string {
    ($var:ident = $value:expr $(,)?) => {
        let mut $var = $crate::private::StackString::new();
        #[allow(unused_mut, unused_unsafe)]
        let mut $var = match $value {
            let_cxx_string => unsafe { $var.init(let_cxx_string) },
        };
    };
}

impl CxxString {
    /// `CxxString` is not constructible via `new`. Instead, use the
    /// [`let_cxx_string!`] macro.
    pub fn new<T: Private>() -> Self {
        unreachable!()
    }

    /// Returns the length of the string in bytes.
    ///
    /// Matches the behavior of C++ [std::string::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/string/basic_string/size
    pub fn len(&self) -> usize {
        unsafe { string_length(self) }
    }

    /// Returns true if `self` has a length of zero bytes.
    ///
    /// Matches the behavior of C++ [std::string::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/string/basic_string/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a byte slice of this string's contents.
    pub fn as_bytes(&self) -> &[u8] {
        let data = self.as_ptr();
        let len = self.len();
        unsafe { slice::from_raw_parts(data, len) }
    }

    /// Produces a pointer to the first character of the string.
    ///
    /// Matches the behavior of C++ [std::string::data][data].
    ///
    /// Note that the return type may look like `const char *` but is not a
    /// `const char *` in the typical C sense, as C++ strings may contain
    /// internal null bytes. As such, the returned pointer only makes sense as a
    /// string in combination with the length returned by [`len()`][len].
    ///
    /// [data]: https://en.cppreference.com/w/cpp/string/basic_string/data
    /// [len]: #method.len
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { string_data(self) }
    }

    /// Validates that the C++ string contains UTF-8 data and produces a view of
    /// it as a Rust &str, otherwise an error.
    pub fn to_str(&self) -> Result<&str, Utf8Error> {
        str::from_utf8(self.as_bytes())
    }

    /// If the contents of the C++ string are valid UTF-8, this function returns
    /// a view as a Cow::Borrowed &str. Otherwise replaces any invalid UTF-8
    /// sequences with the U+FFFD [replacement character] and returns a
    /// Cow::Owned String.
    ///
    /// [replacement character]: https://doc.rust-lang.org/std/char/constant.REPLACEMENT_CHARACTER.html
    pub fn to_string_lossy(&self) -> Cow<str> {
        String::from_utf8_lossy(self.as_bytes())
    }

    /// Appends a given string slice onto the end of this C++ string.
    pub fn push_str(self: Pin<&mut Self>, s: &str) {
        self.push_bytes(s.as_bytes());
    }

    /// Appends arbitrary bytes onto the end of this C++ string.
    pub fn push_bytes(self: Pin<&mut Self>, bytes: &[u8]) {
        unsafe { string_push(self, bytes.as_ptr(), bytes.len()) }
    }
}

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

impl Debug for CxxString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.to_string_lossy().as_ref(), f)
    }
}

impl PartialEq for CxxString {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<CxxString> for str {
    fn eq(&self, other: &CxxString) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl PartialEq<str> for CxxString {
    fn eq(&self, other: &str) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

#[doc(hidden)]
#[repr(C)]
pub struct StackString {
    // Static assertions in cxx.cc validate that this is large enough and
    // aligned enough.
    space: MaybeUninit<[*const (); 8]>,
}

impl StackString {
    pub fn new() -> Self {
        StackString {
            space: MaybeUninit::uninit(),
        }
    }

    pub unsafe fn init(&mut self, value: impl AsRef<[u8]>) -> Pin<&mut CxxString> {
        let value = value.as_ref();
        let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
        string_init(this, value.as_ptr(), value.len());
        Pin::new_unchecked(&mut *this.as_mut_ptr())
    }
}

impl Drop for StackString {
    fn drop(&mut self) {
        unsafe {
            let this = &mut *self.space.as_mut_ptr().cast::<MaybeUninit<CxxString>>();
            string_destroy(this);
        }
    }
}
<|endoftext|>