<commit_before>/*
 * Copyright (c) 2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pub struct AgentController<'a> {
    #[allow(dead_code)] // TODO: revisit this once port is complete
    jvmti: ::env::JvmTiEnv,
    heuristic: Box<super::Heuristic + 'a>,
    actions: Vec<Box<super::Action>>
}

impl<'a> AgentController<'a> {
    pub fn new(ti: ::env::JvmTiEnv, options: *mut ::std::os::raw::c_char) -> Result<Self, ::jvmti::jint> {
        let parms = super::parms::AgentParameters::parseParameters(options);

        let mut ac = Self {
            jvmti: ti,
            heuristic: Box::new(super::threshold::Threshold::new(parms.count_threshold, parms.time_threshold)),
            actions: Vec::new(),
        };

        if parms.print_heap_histogram {
            ac.actions.push(Box::new(super::heaphistogram::HeapHistogram::new(ti, parms.heap_histogram_max_entries)?));
        }

        if let Some(path) = parms.heap_dump_path {
            ac.actions.push(Box::new(super::heapdump::HeapDump::new(path)));
        }

        if parms.print_memory_usage {
            ac.actions.push(Box::new(super::poolstats::PoolStats::new()));
        }

        ac.actions.push(Box::new(super::kill::Kill::new()));

        Ok(ac)
    }

    #[cfg(test)]
    fn test_new(ti: ::env::JvmTiEnv, heuristic: Box<super::Heuristic + 'a>, actions: Vec<Box<super::Action>>) -> Self {
        Self {
            jvmti: ti,
            heuristic: heuristic,
            actions: actions,
        }
    }
}

impl<'a> super::MutAction for AgentController<'a> {
    fn on_oom(&mut self, jni_env: ::env::JniEnv, resource_exhaustion_flags: ::jvmti::jint) {
        const heap_exhausted: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP as ::jvmti::jint;
        const threads_exhausted: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_THREADS as ::jvmti::jint;
        const oom_error: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR as ::jvmti::jint;

        if resource_exhaustion_flags & heap_exhausted == heap_exhausted {
            eprintln!("\nResource exhaustion event: the JVM was unable to allocate memory from the heap.");
        }
        if resource_exhaustion_flags & threads_exhausted == threads_exhausted {
            eprintln!("\nResource exhaustion event: the JVM was unable to create a thread.");
        }

        if self.heuristic.on_oom() {
            for action in &self.actions {
                action.on_oom(jni_env, resource_exhaustion_flags);
            }
        } else if resource_exhaustion_flags & oom_error == oom_error {
            eprintln!("\nThe JVM is about to throw a java.lang.OutOfMemoryError.");
        }
    }
}

unsafe impl<'a> Send for AgentController<'a> {}

unsafe impl<'a> Sync for AgentController<'a> {}

#[cfg(test)]
mod tests {
    use agentcontroller::MutAction;

    pub struct TestHeuristic {
        call_count: u32
    }

    impl TestHeuristic {
        pub fn new() -> Self {
            Self {
                call_count: 0,
            }
        }
    }

    impl super::super::Heuristic for TestHeuristic {
        fn on_oom(&mut self) -> bool {
            self.call_count += 1;
            self.call_count >= 2
        }
    }

    pub struct TestAction {}

    impl TestAction {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl super::super::Action for TestAction {
        fn on_oom(&self, _: ::env::JniEnv, _: ::jvmti::jint) {
            panic!("TestAction.on_oom")
        }
    }

    #[test]
    fn does_not_call_action_when_heuristic_returns_false() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
    }

    #[test]
    #[should_panic(expected = "TestAction.on_oom")]
    fn calls_action_when_heuristic_returns_true() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(::env::JvmTiEnv::new(dummy_jni()).unwrap(),
                                                      heuristic,
                                                      vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
        ac.on_oom(dummy_jni_env(), 0);
    }

    unsafe extern "C" fn test_get_env(_: *mut ::jvmti::JavaVM,
                                      _: *mut *mut ::std::os::raw::c_void,
                                      _: ::jvmti::jint)
                                      -> ::jvmti::jint {
        0
    }

    fn dummy_jni_env() -> ::env::JniEnv {
        ::env::JniEnv::new(::std::ptr::null_mut())
    }

    fn dummy_jni() -> *mut ::jvmti::JavaVM {
        &mut (&::jvmti::JNIInvokeInterface_ {
            reserved0: ::std::ptr::null_mut(),
            reserved1: ::std::ptr::null_mut(),
            reserved2: ::std::ptr::null_mut(),
            DestroyJavaVM: None,
            AttachCurrentThread: None,
            DetachCurrentThread: None,
            GetEnv: Some(test_get_env),
            AttachCurrentThreadAsDaemon: None,
        } as *const ::jvmti::JNIInvokeInterface_) as *mut *const ::jvmti::JNIInvokeInterface_
    }
}
<commit_msg>Tidy up<commit_after>/*
 * Copyright (c) 2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pub struct AgentController<'a> {
    heuristic: Box<super::Heuristic + 'a>,
    actions: Vec<Box<super::Action>>
}

impl<'a> AgentController<'a> {
    pub fn new(ti: ::env::JvmTiEnv, options: *mut ::std::os::raw::c_char) -> Result<Self, ::jvmti::jint> {
        let parms = super::parms::AgentParameters::parseParameters(options);

        let mut ac = Self {
            heuristic: Box::new(super::threshold::Threshold::new(parms.count_threshold, parms.time_threshold)),
            actions: Vec::new(),
        };

        if parms.print_heap_histogram {
            ac.actions.push(Box::new(super::heaphistogram::HeapHistogram::new(ti, parms.heap_histogram_max_entries)?));
        }

        if let Some(path) = parms.heap_dump_path {
            ac.actions.push(Box::new(super::heapdump::HeapDump::new(path)));
        }

        if parms.print_memory_usage {
            ac.actions.push(Box::new(super::poolstats::PoolStats::new()));
        }

        ac.actions.push(Box::new(super::kill::Kill::new()));

        Ok(ac)
    }

    #[cfg(test)]
    fn test_new(heuristic: Box<super::Heuristic + 'a>, actions: Vec<Box<super::Action>>) -> Self {
        Self {
            heuristic: heuristic,
            actions: actions,
        }
    }
}

impl<'a> super::MutAction for AgentController<'a> {
    fn on_oom(&mut self, jni_env: ::env::JniEnv, resource_exhaustion_flags: ::jvmti::jint) {
        const heap_exhausted: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP as ::jvmti::jint;
        const threads_exhausted: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_THREADS as ::jvmti::jint;
        const oom_error: ::jvmti::jint = ::jvmti::JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR as ::jvmti::jint;

        if resource_exhaustion_flags & heap_exhausted == heap_exhausted {
            eprintln!("\nResource exhaustion event: the JVM was unable to allocate memory from the heap.");
        }
        if resource_exhaustion_flags & threads_exhausted == threads_exhausted {
            eprintln!("\nResource exhaustion event: the JVM was unable to create a thread.");
        }

        if self.heuristic.on_oom() {
            for action in &self.actions {
                action.on_oom(jni_env, resource_exhaustion_flags);
            }
        } else if resource_exhaustion_flags & oom_error == oom_error {
            eprintln!("\nThe JVM is about to throw a java.lang.OutOfMemoryError.");
        }
    }
}

unsafe impl<'a> Send for AgentController<'a> {}

unsafe impl<'a> Sync for AgentController<'a> {}

#[cfg(test)]
mod tests {
    use agentcontroller::MutAction;

    pub struct TestHeuristic {
        call_count: u32
    }

    impl TestHeuristic {
        pub fn new() -> Self {
            Self {
                call_count: 0,
            }
        }
    }

    impl super::super::Heuristic for TestHeuristic {
        fn on_oom(&mut self) -> bool {
            self.call_count += 1;
            self.call_count >= 2
        }
    }

    pub struct TestAction {}

    impl TestAction {
        pub fn new() -> Self {
            Self {}
        }
    }

    impl super::super::Action for TestAction {
        fn on_oom(&self, _: ::env::JniEnv, _: ::jvmti::jint) {
            panic!("TestAction.on_oom")
        }
    }

    #[test]
    fn does_not_call_action_when_heuristic_returns_false() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(heuristic, vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
    }

    #[test]
    #[should_panic(expected = "TestAction.on_oom")]
    fn calls_action_when_heuristic_returns_true() {
        let heuristic = Box::new(TestHeuristic::new());
        let mut ac = super::AgentController::test_new(heuristic, vec![Box::new(TestAction::new())]);
        ac.on_oom(dummy_jni_env(), 0);
        ac.on_oom(dummy_jni_env(), 0);
    }

    fn dummy_jni_env() -> ::env::JniEnv {
        ::env::JniEnv::new(::std::ptr::null_mut())
    }
}
<|endoftext|>


<commit_before>extern crate config;
extern crate pretty_env_logger;
#[macro_use]
extern crate log;

use tokio::join;
use tokio::net::TcpListener;
use tokio::net::TcpSocket;
use tokio::net::TcpStream;
use tokio::task;

use std::collections::HashMap;

use std::io;

type HashAddressInfo = HashMap<String, HashMap<String, String>>;
type HashContainsYaml = HashMap<String, HashAddressInfo>;

async fn forward(mut stream_origin: TcpStream, output_address: &str) -> io::Result<()> {
    let socket_output = TcpSocket::new_v4()?;
    let mut stream_output = socket_output
        .connect(output_address.parse().expect("Unable parse socket address"))
        .await?;
    let (mut stream_origin_recv, mut stream_origin_send) = stream_origin.split();
    let (mut stream_output_recv, mut stream_output_send) = stream_output.split();
    let (stream_origin_bytes_copied, stream_output_bytes_copied) = join!(
        tokio::io::copy(&mut stream_origin_recv, &mut stream_output_send),
        tokio::io::copy(&mut stream_output_recv, &mut stream_origin_send),
    );

    if let Ok(count) = stream_origin_bytes_copied {
        info!("Stream origin transfered bytes: {}", count);
    } else {
        error!("Stream origin error transfering bytes");
    }

    if let Ok(count) = stream_output_bytes_copied {
        info!("Stream output transfered bytes: {}", count);
    } else {
        error!("Stream output eError transfering bytes");
    }

    Ok(())
}

pub struct Host {
    host: String,
    port: i32,
}

pub struct RuleConfig {
    name: String,
    input: Host,
    output: Host,
}

fn load_config(config_file: &str) -> Vec<RuleConfig> {
    let mut settings = config::Config::default();
    settings
        .merge(config::File::with_name(config_file))
        .unwrap();
    let mut doc = settings.try_into::<HashContainsYaml>().unwrap();

    let mut rules: Vec<RuleConfig> = Vec::new();
    for (name, value) in doc.iter_mut() {
        let address_input = value.clone().get_mut("input").map_or(
            Host {
                host: "".to_owned(),
                port: 0,
            },
            |v| Host {
                host: v["host"].clone(),
                port: v["port"].clone().parse::<i32>().unwrap(),
            },
        );
        let address_output = value.clone().get_mut("output").map_or(
            Host {
                host: "".to_owned(),
                port: 0,
            },
            |v| Host {
                host: v["host"].clone(),
                port: v["port"].clone().parse::<i32>().unwrap(),
            },
        );

        rules.push(RuleConfig {
            name: name.to_string(),
            input: address_input,
            output: address_output,
        });
    }

    return rules;
}

#[tokio::main]
async fn main() -> io::Result<()> {
    let config_file: &str = "/home/carlosb/rust-workspace/examples-rust/reverse-proxy/config.yml";
    let rule_configs = load_config(config_file);

    pretty_env_logger::init();

    for rule in rule_configs {
        let input_host = rule.input.host;
        let input_port = rule.input.port;
        let output_host = rule.output.host;
        let output_port = rule.output.port;

        let join = task::spawn(async {});

        /*
        let join = task::spawn(async {
            let output_address = format!("{}:{}", output_host, output_host);
            let input_address = format!("{}:{}", input_host, input_host);
            let listener = TcpListener::bind(output_address).await?;
            loop {
                let (socket, _) = listener.accept().await?;
                forward(socket, input_address.as_str()).await?;
            }
        });
        join.await;
        */
    }
    Ok(())
}
<commit_msg>Added tokio tasks to manage different threads<commit_after>extern crate config;
extern crate pretty_env_logger;
#[macro_use]
extern crate log;

use futures::future::join_all;

use tokio::join;
use tokio::net::TcpListener;
use tokio::net::TcpSocket;
use tokio::net::TcpStream;
use tokio::task;

use std::collections::HashMap;

use std::io;

type HashAddressInfo = HashMap<String, HashMap<String, String>>;
type HashContainsYaml = HashMap<String, HashAddressInfo>;

async fn forward(mut stream_origin: TcpStream, output_address: &str) -> io::Result<()> {
    let socket_output = TcpSocket::new_v4()?;
    let mut stream_output = socket_output
        .connect(output_address.parse().expect("Unable parse socket address"))
        .await?;
    let (mut stream_origin_recv, mut stream_origin_send) = stream_origin.split();
    let (mut stream_output_recv, mut stream_output_send) = stream_output.split();
    let (stream_origin_bytes_copied, stream_output_bytes_copied) = join!(
        tokio::io::copy(&mut stream_origin_recv, &mut stream_output_send),
        tokio::io::copy(&mut stream_output_recv, &mut stream_origin_send),
    );

    if let Ok(count) = stream_origin_bytes_copied {
        info!("Stream origin transfered bytes: {}", count);
    } else {
        error!("Stream origin error transfering bytes");
    }

    if let Ok(count) = stream_output_bytes_copied {
        info!("Stream output transfered bytes: {}", count);
    } else {
        error!("Stream output eError transfering bytes");
    }

    Ok(())
}

pub struct Host {
    host: String,
    port: i32,
}

pub struct RuleConfig {
    name: String,
    input: Host,
    output: Host,
}

fn load_config(config_file: &str) -> Vec<RuleConfig> {
    let mut settings = config::Config::default();
    settings
        .merge(config::File::with_name(config_file))
        .unwrap();
    let mut doc = settings.try_into::<HashContainsYaml>().unwrap();

    let mut rules: Vec<RuleConfig> = Vec::new();
    for (name, value) in doc.iter_mut() {
        let address_input = value.clone().get_mut("input").map_or(
            Host {
                host: "".to_owned(),
                port: 0,
            },
            |v| Host {
                host: v["host"].clone(),
                port: v["port"].clone().parse::<i32>().unwrap(),
            },
        );
        let address_output = value.clone().get_mut("output").map_or(
            Host {
                host: "".to_owned(),
                port: 0,
            },
            |v| Host {
                host: v["host"].clone(),
                port: v["port"].clone().parse::<i32>().unwrap(),
            },
        );

        rules.push(RuleConfig {
            name: name.to_string(),
            input: address_input,
            output: address_output,
        });
    }

    return rules;
}

#[tokio::main]
async fn main() -> io::Result<()> {
    let config_file: &str = "/home/carlosb/rust-workspace/examples-rust/reverse-proxy/config.yml";
    let rule_configs = load_config(config_file);

    pretty_env_logger::init();

    let mut joins = Vec::new();
    for rule in rule_configs {
        let input_host = rule.input.host;
        let input_port = rule.input.port;
        let output_host = rule.output.host;
        let output_port = rule.output.port;

        let join = task::spawn(async move {
            let output_address = format!("{}:{}", output_host, output_port);
            let input_address = format!("{}:{}", input_host, input_port);
            let listener = TcpListener::bind(output_address.clone())
                .await
                .expect(format!("Error binding address {}", output_address).as_str());
            //TODO loop to wait for connection, is it needed this loop?
            loop {
                let (socket, _) = listener.accept().await.unwrap();
                forward(socket, input_address.as_str()).await.unwrap();
            }
        });
        joins.push(join);
    }
    join_all(joins).await;
    Ok(())
}
<|endoftext|>


<commit_before>use crate::{Address, Epoch, Hash256, Slot};
use bls::Signature;

const GWEI: u64 = 1_000_000_000;

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.2.0
#[derive(PartialEq, Debug, Clone)]
pub struct ChainSpec {
    /*
     * Misc
     */
    pub shard_count: u64,
    pub target_committee_size: u64,
    pub max_balance_churn_quotient: u64,
    pub beacon_chain_shard_number: u64,
    pub max_indices_per_slashable_vote: u64,
    pub max_withdrawals_per_epoch: u64,
    pub shuffle_round_count: u8,

    /*
     *  Deposit contract
     */
    pub deposit_contract_address: Address,
    pub deposit_contract_tree_depth: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_deposit_amount: u64,
    pub fork_choice_balance_increment: u64,
    pub ejection_balance: u64,

    /*
     * Initial Values
     */
    pub genesis_fork_version: u64,
    pub genesis_slot: Slot,
    pub genesis_epoch: Epoch,
    pub genesis_start_shard: u64,
    pub far_future_epoch: Epoch,
    pub zero_hash: Hash256,
    pub empty_signature: Signature,
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub slot_duration: u64,
    pub min_attestation_inclusion_delay: u64,
    pub epoch_length: u64,
    pub seed_lookahead: Epoch,
    pub entry_exit_delay: u64,
    pub eth1_data_voting_period: u64,
    pub min_validator_withdrawal_epochs: Epoch,

    /*
     * State list lengths
     */
    pub latest_block_roots_length: usize,
    pub latest_randao_mixes_length: usize,
    pub latest_index_roots_length: usize,
    pub latest_penalized_exit_length: usize,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_quotient: u64,
    pub whistleblower_reward_quotient: u64,
    pub includer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,

    /*
     * Max operations per block
     */
    pub max_proposer_slashings: u64,
    pub max_attester_slashings: u64,
    pub max_attestations: u64,
    pub max_deposits: u64,
    pub max_exits: u64,

    /*
     * Signature domains
     */
    pub domain_deposit: u64,
    pub domain_attestation: u64,
    pub domain_proposal: u64,
    pub domain_exit: u64,
    pub domain_randao: u64,
}

impl ChainSpec {
    /// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
    ///
    /// Of course, the actual foundation specs are unknown at this point so these are just a rough
    /// estimate.
    ///
    /// Spec v0.2.0
    pub fn foundation() -> Self {
        let genesis_slot = Slot::new(2_u64.pow(19));
        let epoch_length = 64;
        let genesis_epoch = genesis_slot.epoch(epoch_length);

        Self {
            /*
             * Misc
             */
            shard_count: 1_024,
            target_committee_size: 128,
            max_balance_churn_quotient: 32,
            beacon_chain_shard_number: u64::max_value(),
            max_indices_per_slashable_vote: 4_096,
            max_withdrawals_per_epoch: 4,
            shuffle_round_count: 90,

            /*
             *  Deposit contract
             */
            deposit_contract_address: Address::zero(),
            deposit_contract_tree_depth: 32,

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * GWEI,
            max_deposit_amount: u64::pow(2, 5) * GWEI,
            fork_choice_balance_increment: u64::pow(2, 0) * GWEI,
            ejection_balance: u64::pow(2, 4) * GWEI,

            /*
             * Initial Values
             */
            genesis_fork_version: 0,
            genesis_slot: Slot::new(2_u64.pow(19)),
            genesis_epoch,
            genesis_start_shard: 0,
            far_future_epoch: Epoch::new(u64::max_value()),
            zero_hash: Hash256::zero(),
            empty_signature: Signature::empty_signature(),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            slot_duration: 6,
            min_attestation_inclusion_delay: 4,
            epoch_length,
            seed_lookahead: Epoch::new(1),
            entry_exit_delay: 4,
            eth1_data_voting_period: 16,
            min_validator_withdrawal_epochs: Epoch::new(256),

            /*
             * State list lengths
             */
            latest_block_roots_length: 8_192,
            latest_randao_mixes_length: 8_192,
            latest_index_roots_length: 8_192,
            latest_penalized_exit_length: 8_192,

            /*
             * Reward and penalty quotients
             */
            base_reward_quotient: 32,
            whistleblower_reward_quotient: 512,
            includer_reward_quotient: 8,
            inactivity_penalty_quotient: 16_777_216,

            /*
             * Max operations per block
             */
            max_proposer_slashings: 16,
            max_attester_slashings: 1,
            max_attestations: 128,
            max_deposits: 16,
            max_exits: 16,

            /*
             * Signature domains
             */
            domain_deposit: 0,
            domain_attestation: 1,
            domain_proposal: 2,
            domain_exit: 3,
            domain_randao: 4,
        }
    }
}

impl ChainSpec {
    /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators.
    ///
    /// Spec v0.2.0
    pub fn few_validators() -> Self {
        let genesis_slot = Slot::new(2_u64.pow(19));
        let epoch_length = 8;
        let genesis_epoch = genesis_slot.epoch(epoch_length);

        Self {
            shard_count: 1,
            target_committee_size: 1,
            genesis_slot,
            genesis_epoch,
            epoch_length,
            ..ChainSpec::foundation()
        }
    }
}

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

    #[test]
    fn test_foundation_spec_can_be_constructed() {
        let _ = ChainSpec::foundation();
    }
}
<commit_msg>Change "few_validators" spec to be 8 shards.<commit_after>use crate::{Address, Epoch, Hash256, Slot};
use bls::Signature;

const GWEI: u64 = 1_000_000_000;

/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.2.0
#[derive(PartialEq, Debug, Clone)]
pub struct ChainSpec {
    /*
     * Misc
     */
    pub shard_count: u64,
    pub target_committee_size: u64,
    pub max_balance_churn_quotient: u64,
    pub beacon_chain_shard_number: u64,
    pub max_indices_per_slashable_vote: u64,
    pub max_withdrawals_per_epoch: u64,
    pub shuffle_round_count: u8,

    /*
     *  Deposit contract
     */
    pub deposit_contract_address: Address,
    pub deposit_contract_tree_depth: u64,

    /*
     *  Gwei values
     */
    pub min_deposit_amount: u64,
    pub max_deposit_amount: u64,
    pub fork_choice_balance_increment: u64,
    pub ejection_balance: u64,

    /*
     * Initial Values
     */
    pub genesis_fork_version: u64,
    pub genesis_slot: Slot,
    pub genesis_epoch: Epoch,
    pub genesis_start_shard: u64,
    pub far_future_epoch: Epoch,
    pub zero_hash: Hash256,
    pub empty_signature: Signature,
    pub bls_withdrawal_prefix_byte: u8,

    /*
     * Time parameters
     */
    pub slot_duration: u64,
    pub min_attestation_inclusion_delay: u64,
    pub epoch_length: u64,
    pub seed_lookahead: Epoch,
    pub entry_exit_delay: u64,
    pub eth1_data_voting_period: u64,
    pub min_validator_withdrawal_epochs: Epoch,

    /*
     * State list lengths
     */
    pub latest_block_roots_length: usize,
    pub latest_randao_mixes_length: usize,
    pub latest_index_roots_length: usize,
    pub latest_penalized_exit_length: usize,

    /*
     * Reward and penalty quotients
     */
    pub base_reward_quotient: u64,
    pub whistleblower_reward_quotient: u64,
    pub includer_reward_quotient: u64,
    pub inactivity_penalty_quotient: u64,

    /*
     * Max operations per block
     */
    pub max_proposer_slashings: u64,
    pub max_attester_slashings: u64,
    pub max_attestations: u64,
    pub max_deposits: u64,
    pub max_exits: u64,

    /*
     * Signature domains
     */
    pub domain_deposit: u64,
    pub domain_attestation: u64,
    pub domain_proposal: u64,
    pub domain_exit: u64,
    pub domain_randao: u64,
}

impl ChainSpec {
    /// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
    ///
    /// Of course, the actual foundation specs are unknown at this point so these are just a rough
    /// estimate.
    ///
    /// Spec v0.2.0
    pub fn foundation() -> Self {
        let genesis_slot = Slot::new(2_u64.pow(19));
        let epoch_length = 64;
        let genesis_epoch = genesis_slot.epoch(epoch_length);

        Self {
            /*
             * Misc
             */
            shard_count: 1_024,
            target_committee_size: 128,
            max_balance_churn_quotient: 32,
            beacon_chain_shard_number: u64::max_value(),
            max_indices_per_slashable_vote: 4_096,
            max_withdrawals_per_epoch: 4,
            shuffle_round_count: 90,

            /*
             *  Deposit contract
             */
            deposit_contract_address: Address::zero(),
            deposit_contract_tree_depth: 32,

            /*
             *  Gwei values
             */
            min_deposit_amount: u64::pow(2, 0) * GWEI,
            max_deposit_amount: u64::pow(2, 5) * GWEI,
            fork_choice_balance_increment: u64::pow(2, 0) * GWEI,
            ejection_balance: u64::pow(2, 4) * GWEI,

            /*
             * Initial Values
             */
            genesis_fork_version: 0,
            genesis_slot: Slot::new(2_u64.pow(19)),
            genesis_epoch,
            genesis_start_shard: 0,
            far_future_epoch: Epoch::new(u64::max_value()),
            zero_hash: Hash256::zero(),
            empty_signature: Signature::empty_signature(),
            bls_withdrawal_prefix_byte: 0,

            /*
             * Time parameters
             */
            slot_duration: 6,
            min_attestation_inclusion_delay: 4,
            epoch_length,
            seed_lookahead: Epoch::new(1),
            entry_exit_delay: 4,
            eth1_data_voting_period: 16,
            min_validator_withdrawal_epochs: Epoch::new(256),

            /*
             * State list lengths
             */
            latest_block_roots_length: 8_192,
            latest_randao_mixes_length: 8_192,
            latest_index_roots_length: 8_192,
            latest_penalized_exit_length: 8_192,

            /*
             * Reward and penalty quotients
             */
            base_reward_quotient: 32,
            whistleblower_reward_quotient: 512,
            includer_reward_quotient: 8,
            inactivity_penalty_quotient: 16_777_216,

            /*
             * Max operations per block
             */
            max_proposer_slashings: 16,
            max_attester_slashings: 1,
            max_attestations: 128,
            max_deposits: 16,
            max_exits: 16,

            /*
             * Signature domains
             */
            domain_deposit: 0,
            domain_attestation: 1,
            domain_proposal: 2,
            domain_exit: 3,
            domain_randao: 4,
        }
    }
}

impl ChainSpec {
    /// Returns a `ChainSpec` compatible with the specification suitable for 8 validators.
    ///
    /// Spec v0.2.0
    pub fn few_validators() -> Self {
        let genesis_slot = Slot::new(2_u64.pow(19));
        let epoch_length = 8;
        let genesis_epoch = genesis_slot.epoch(epoch_length);

        Self {
            shard_count: 8,
            target_committee_size: 1,
            genesis_slot,
            genesis_epoch,
            epoch_length,
            ..ChainSpec::foundation()
        }
    }
}

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

    #[test]
    fn test_foundation_spec_can_be_constructed() {
        let _ = ChainSpec::foundation();
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate sysinfo;
extern crate test;

use sysinfo::get_current_pid;
use sysinfo::SystemExt;

#[bench]
fn bench_new(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new();
    });
}

#[bench]
fn bench_new_all(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new_all();
    });
}

#[bench]
fn bench_refresh_all(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_all();
    });
}

#[bench]
fn bench_refresh_system(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    s.refresh_system();
    b.iter(move || {
        s.refresh_system();
    });
}

#[bench]
fn bench_refresh_processes(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_processes(); // to load the whole processes list a first time.
    b.iter(move || {
        s.refresh_processes();
    });
}

#[bench]
fn bench_refresh_process(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_all();
    // to be sure it'll exist for at least as long as we run
    let pid = get_current_pid().expect("failed to get current pid");
    b.iter(move || {
        s.refresh_process(pid, );
    });
}

#[bench]
fn bench_refresh_disks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_disks();
    });
}

#[bench]
fn bench_refresh_disks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_disks_list();
    });
}

#[bench]
fn bench_refresh_networks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_networks();
    });
}

#[bench]
fn bench_refresh_networks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_networks_list();
    });
}

#[bench]
fn bench_refresh_memory(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_memory();
    });
}

#[bench]
fn bench_refresh_cpu(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_cpu();
    });
}

#[bench]
fn bench_refresh_components(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components();
    });
}

#[bench]
fn bench_refresh_components_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components_list();
    });
}

#[bench]
fn bench_refresh_users_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_users_list();
    });
}
<commit_msg>Add bench for refreshing one disk<commit_after>#![feature(test)]

extern crate sysinfo;
extern crate test;

use sysinfo::get_current_pid;
use sysinfo::{DiskExt, SystemExt};

#[bench]
fn bench_new(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new();
    });
}

#[bench]
fn bench_new_all(b: &mut test::Bencher) {
    b.iter(|| {
        sysinfo::System::new_all();
    });
}

#[bench]
fn bench_refresh_all(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_all();
    });
}

#[bench]
fn bench_refresh_system(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    s.refresh_system();
    b.iter(move || {
        s.refresh_system();
    });
}

#[bench]
fn bench_refresh_processes(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_processes(); // to load the whole processes list a first time.
    b.iter(move || {
        s.refresh_processes();
    });
}

#[bench]
fn bench_refresh_process(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    s.refresh_all();
    // to be sure it'll exist for at least as long as we run
    let pid = get_current_pid().expect("failed to get current pid");
    b.iter(move || {
        s.refresh_process(pid, );
    });
}

#[bench]
fn bench_refresh_disk(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    let disks = s.get_disks_mut();
    let disk = &mut disks[0];
    b.iter(move || {
        disk.refresh();
    });
}

#[bench]
fn bench_refresh_disks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_disks();
    });
}

#[bench]
fn bench_refresh_disks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_disks_list();
    });
}

#[bench]
fn bench_refresh_networks(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_networks();
    });
}

#[bench]
fn bench_refresh_networks_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_networks_list();
    });
}

#[bench]
fn bench_refresh_memory(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_memory();
    });
}

#[bench]
fn bench_refresh_cpu(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new();

    b.iter(move || {
        s.refresh_cpu();
    });
}

#[bench]
fn bench_refresh_components(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components();
    });
}

#[bench]
fn bench_refresh_components_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_components_list();
    });
}

#[bench]
fn bench_refresh_users_list(b: &mut test::Bencher) {
    let mut s = sysinfo::System::new_all();

    b.iter(move || {
        s.refresh_users_list();
    });
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;

use std::hash::Hash;
use test::Bencher;

use hashbrown::HashMap;
//use rustc_hash::FxHashMap as HashMap;
//use std::collections::HashMap;

fn new_map<K: Eq + Hash, V>() -> HashMap<K, V> {
    HashMap::default()
}

#[bench]
fn new_drop(b: &mut Bencher) {
    b.iter(|| {
        let m: HashMap<i32, i32> = new_map();
        assert_eq!(m.len(), 0);
    })
}

#[bench]
fn new_insert_drop(b: &mut Bencher) {
    b.iter(|| {
        let mut m = new_map();
        m.insert(0, 0);
        assert_eq!(m.len(), 1);
    })
}

#[bench]
fn grow_by_insertion(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1001;

    b.iter(|| {
        m.insert(k, k);
        k += 1;
    });
}

#[bench]
fn grow_by_insertion_kb(b: &mut Bencher) {
    let mut m = new_map();
    let kb = 1024;
    for i in 1..1001 {
        m.insert(i * kb, i);
    }

    let mut k = 1001 * kb;

    b.iter(|| {
        m.insert(k, k);
        k += kb;
    });
}

#[bench]
fn find_existing(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1..1001 {
            m.contains_key(&i);
        }
    });
}

#[bench]
fn find_existing_high_bits(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001_u64 {
        m.insert(i << 32, i);
    }

    b.iter(|| {
        for i in 1..1001_u64 {
            m.contains_key(&(i << 32));
        }
    });
}

#[bench]
fn find_nonexisting(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1001..2001 {
            m.contains_key(&i);
        }
    });
}

#[bench]
fn hashmap_as_queue(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1;

    b.iter(|| {
        m.remove(&k);
        m.insert(k + 1000, k + 1000);
        k += 1;
    });
}

#[bench]
fn get_remove_insert(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1;

    b.iter(|| {
        m.get(&(k + 400));
        m.get(&(k + 2000));
        m.remove(&k);
        m.insert(k + 1000, k + 1000);
        k += 1;
    })
}

#[bench]
fn insert_8_char_string(b: &mut Bencher) {
    let mut strings: Vec<_> = Vec::new();
    for i in 1..1001 {
        strings.push(format!("{:x}", -i));
    }

    let mut m = new_map();
    b.iter(|| {
        for key in &strings {
            m.insert(key, key);
        }
    })

}<commit_msg>Formatting<commit_after>#![feature(test)]

extern crate test;

use std::hash::Hash;
use test::Bencher;

use hashbrown::HashMap;
//use rustc_hash::FxHashMap as HashMap;
//use std::collections::HashMap;

fn new_map<K: Eq + Hash, V>() -> HashMap<K, V> {
    HashMap::default()
}

#[bench]
fn new_drop(b: &mut Bencher) {
    b.iter(|| {
        let m: HashMap<i32, i32> = new_map();
        assert_eq!(m.len(), 0);
    })
}

#[bench]
fn new_insert_drop(b: &mut Bencher) {
    b.iter(|| {
        let mut m = new_map();
        m.insert(0, 0);
        assert_eq!(m.len(), 1);
    })
}

#[bench]
fn grow_by_insertion(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1001;

    b.iter(|| {
        m.insert(k, k);
        k += 1;
    });
}

#[bench]
fn grow_by_insertion_kb(b: &mut Bencher) {
    let mut m = new_map();
    let kb = 1024;
    for i in 1..1001 {
        m.insert(i * kb, i);
    }

    let mut k = 1001 * kb;

    b.iter(|| {
        m.insert(k, k);
        k += kb;
    });
}

#[bench]
fn find_existing(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1..1001 {
            m.contains_key(&i);
        }
    });
}

#[bench]
fn find_existing_high_bits(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001_u64 {
        m.insert(i << 32, i);
    }

    b.iter(|| {
        for i in 1..1001_u64 {
            m.contains_key(&(i << 32));
        }
    });
}

#[bench]
fn find_nonexisting(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1001..2001 {
            m.contains_key(&i);
        }
    });
}

#[bench]
fn hashmap_as_queue(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1;

    b.iter(|| {
        m.remove(&k);
        m.insert(k + 1000, k + 1000);
        k += 1;
    });
}

#[bench]
fn get_remove_insert(b: &mut Bencher) {
    let mut m = new_map();

    for i in 1..1001 {
        m.insert(i, i);
    }

    let mut k = 1;

    b.iter(|| {
        m.get(&(k + 400));
        m.get(&(k + 2000));
        m.remove(&k);
        m.insert(k + 1000, k + 1000);
        k += 1;
    })
}

#[bench]
fn insert_8_char_string(b: &mut Bencher) {
    let mut strings: Vec<_> = Vec::new();
    for i in 1..1001 {
        strings.push(format!("{:x}", -i));
    }

    let mut m = new_map();
    b.iter(|| {
        for key in &strings {
            m.insert(key, key);
        }
    })
}
<|endoftext|>


<commit_before>//! A simplified implementation of the `bytes` crate, with different features, less safety.
//!
//! #Examples
//!
//! ```
//! use bytes::rc::Bytes;
//!
//! let bytes = vec![0u8; 1024];
//! let mut shared1 = Bytes::from(bytes);
//! let mut shared2 = shared1.extract_to(100);
//! let mut shared3 = shared1.extract_to(100);
//! let mut shared4 = shared2.extract_to(60);
//!
//! assert_eq!(shared1.len(), 824);
//! assert_eq!(shared2.len(), 40);
//! assert_eq!(shared3.len(), 100);
//! assert_eq!(shared4.len(), 60);
//!
//! for byte in shared1.iter_mut() { *byte = 1u8; }
//! for byte in shared2.iter_mut() { *byte = 2u8; }
//! for byte in shared3.iter_mut() { *byte = 3u8; }
//! for byte in shared4.iter_mut() { *byte = 4u8; }
//!
//! drop(shared1);
//! drop(shared2);
//! drop(shared3);
//!
//! if let Ok(bytes) = shared4.try_recover::<Vec<u8>>() {
//!     assert_eq!(bytes[200..1024].to_vec(), [1u8;824].to_vec());
//!     assert_eq!(bytes[60..100].to_vec(),   [2u8;40].to_vec());
//!     assert_eq!(bytes[100..200].to_vec(),  [3u8;100].to_vec());
//!     assert_eq!(bytes[0..60].to_vec(),     [4u8;60].to_vec());
//! }
//! else {
//!     panic!("unrecoverable!");
//! }
//! ```
#![forbid(missing_docs)]

/// An `Rc`-backed mutable byte slice backed by a common allocation.
pub mod rc {

    use std::ops::{Deref, DerefMut};
    use std::rc::Rc;
    use std::any::Any;

    /// A thread-local byte buffer backed by a shared allocation.
    pub struct Bytes {
        /// Pointer to the start of this slice (not the allocation).
        ptr: *mut u8,
        /// Length of this slice.
        len: usize,
        /// Shared access to underlying resources.
        ///
        /// Importantly, this is unavailable for as long as the struct exists, which may
        /// prevent shared access to ptr[0 .. len]. I'm not sure I understand Rust's rules
        /// enough to make a strong statement about this.
        sequestered: Rc<Box<Any>>,
    }

    impl Bytes {

        /// Create a new instance from a byte allocation.
        pub fn from<B>(bytes: B) -> Bytes where B: DerefMut<Target=[u8]>+'static {

            let mut boxed = Box::new(bytes) as Box<Any>;

            let ptr = boxed.downcast_mut::<B>().unwrap().as_mut_ptr();
            let len = boxed.downcast_ref::<B>().unwrap().len();
            let sequestered = Rc::new(boxed);

            Bytes {
                ptr,
                len,
                sequestered,
            }
        }

        /// Extracts [0, index) into a new `Bytes` which is returned, updating `self`.
        ///
        /// #Safety
        ///
        /// This method uses an `unsafe` region to advance the pointer by `index`. It first
        /// tests `index` against `self.len`, which should ensure that the offset is in-bounds.
        pub fn extract_to(&mut self, index: usize) -> Bytes {

            assert!(index <= self.len);

            let result = Bytes {
                ptr: self.ptr,
                len: index,
                sequestered: self.sequestered.clone(),
            };

            unsafe { self.ptr = self.ptr.offset(index as isize); }
            self.len -= index;

            result
        }

        /// Recover the underlying storage.
        ///
        /// This method either results in the underlying storage if it is uniquely held, or the
        /// input `Bytes` if it is not uniquely held.
        pub fn try_recover<B>(self) -> Result<B, Bytes> where B: DerefMut<Target=[u8]>+'static {
            match Rc::try_unwrap(self.sequestered) {
                Ok(bytes) => Ok(*bytes.downcast::<B>().unwrap()),
                Err(rc) => Err(Bytes {
                    ptr: self.ptr,
                    len: self.len,
                    sequestered: rc,
                }),
            }
        }
    }

    impl Deref for Bytes {
        type Target = [u8];
        fn deref(&self) -> &[u8] {
            unsafe { ::std::slice::from_raw_parts(self.ptr, self.len) }
        }
    }

    impl DerefMut for Bytes {
        fn deref_mut(&mut self) -> &mut [u8] {
            unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.len) }
        }
    }
}

/// An `Arc`-backed mutable byte slice backed by a common allocation.
pub mod arc {

    use std::ops::{Deref, DerefMut};
    use std::sync::Arc;
    use std::any::Any;

    /// A thread-safe byte buffer backed by a shared allocation.
    pub struct Bytes {
        /// Pointer to the start of this slice (not the allocation).
        ptr: *mut u8,
        /// Length of this slice.
        len: usize,
        /// Shared access to underlying resources.
        ///
        /// Importantly, this is unavailable for as long as the struct exists, which may
        /// prevent shared access to ptr[0 .. len]. I'm not sure I understand Rust's rules
        /// enough to make a strong statement about this.
        sequestered: Arc<Box<Any>>,
    }

    unsafe impl Send for Bytes { }

    impl Bytes {

        /// Create a new instance from a byte allocation.
        pub fn from<B>(bytes: B) -> Bytes where B : DerefMut<Target=[u8]>+'static {

            let mut boxed = Box::new(bytes) as Box<Any>;

            let ptr = boxed.downcast_mut::<B>().unwrap().as_mut_ptr();
            let len = boxed.downcast_ref::<B>().unwrap().len();
            let sequestered = Arc::new(boxed);

            Bytes {
                ptr,
                len,
                sequestered,
            }
        }

        /// Extracts [0, index) into a new `Bytes` which is returned, updating `self`.
        ///
        /// #Safety
        ///
        /// This method uses an `unsafe` region to advance the pointer by `index`. It first
        /// tests `index` against `self.len`, which should ensure that the offset is in-bounds.
        pub fn extract_to(&mut self, index: usize) -> Bytes {

            assert!(index <= self.len);

            let result = Bytes {
                ptr: self.ptr,
                len: index,
                sequestered: self.sequestered.clone(),
            };

            unsafe { self.ptr = self.ptr.offset(index as isize); }
            self.len -= index;

            result
        }

        /// Recover the underlying storage.
        ///
        /// This method either results in the underlying storage if it is uniquely held, or the
        /// input `Bytes` if it is not uniquely held.
        pub fn try_recover<B>(self) -> Result<B, Bytes> where B: DerefMut<Target=[u8]>+'static {
            // println!("Trying recovery; strong count: {:?}", Arc::strong_count(&self.sequestered));
            match Arc::try_unwrap(self.sequestered) {
                Ok(bytes) => Ok(*bytes.downcast::<B>().unwrap()),
                Err(arc) => Err(Bytes {
                    ptr: self.ptr,
                    len: self.len,
                    sequestered: arc,
                }),
            }
        }

        /// Regenerates the Bytes if it is uniquely held.
        ///
        /// If uniquely held, this method recovers the initial pointer and length
        /// of the sequestered allocation and re-initialized the Bytes. The return
        /// value indicates whether this occurred.
        pub fn try_regenerate<B>(&mut self) -> bool where B: DerefMut<Target=[u8]>+'static {
            if let Some(boxed) = Arc::get_mut(&mut self.sequestered) {
                let downcast = boxed.downcast_mut::<B>().expect("Downcast failed");
                self.ptr = downcast.as_mut_ptr();
                self.len = downcast.len();
                true
            }
            else {
                false
            }
        }
    }

    impl Deref for Bytes {
        type Target = [u8];
        fn deref(&self) -> &[u8] {
            unsafe { ::std::slice::from_raw_parts(self.ptr, self.len) }
        }
    }

    impl DerefMut for Bytes {
        fn deref_mut(&mut self) -> &mut [u8] {
            unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.len) }
        }
    }
}
<commit_msg>add try_merge functionality<commit_after>//! A simplified implementation of the `bytes` crate, with different features, less safety.
//!
//! #Examples
//!
//! ```
//! use bytes::rc::Bytes;
//!
//! let bytes = vec![0u8; 1024];
//! let mut shared1 = Bytes::from(bytes);
//! let mut shared2 = shared1.extract_to(100);
//! let mut shared3 = shared1.extract_to(100);
//! let mut shared4 = shared2.extract_to(60);
//!
//! assert_eq!(shared1.len(), 824);
//! assert_eq!(shared2.len(), 40);
//! assert_eq!(shared3.len(), 100);
//! assert_eq!(shared4.len(), 60);
//!
//! for byte in shared1.iter_mut() { *byte = 1u8; }
//! for byte in shared2.iter_mut() { *byte = 2u8; }
//! for byte in shared3.iter_mut() { *byte = 3u8; }
//! for byte in shared4.iter_mut() { *byte = 4u8; }
//!
//! drop(shared1);
//! drop(shared2);
//! drop(shared3);
//!
//! if let Ok(bytes) = shared4.try_recover::<Vec<u8>>() {
//!     assert_eq!(bytes[200..1024].to_vec(), [1u8;824].to_vec());
//!     assert_eq!(bytes[60..100].to_vec(),   [2u8;40].to_vec());
//!     assert_eq!(bytes[100..200].to_vec(),  [3u8;100].to_vec());
//!     assert_eq!(bytes[0..60].to_vec(),     [4u8;60].to_vec());
//! }
//! else {
//!     panic!("unrecoverable!");
//! }
//! ```
#![forbid(missing_docs)]

/// An `Rc`-backed mutable byte slice backed by a common allocation.
pub mod rc {

    use std::ops::{Deref, DerefMut};
    use std::rc::Rc;
    use std::any::Any;

    /// A thread-local byte buffer backed by a shared allocation.
    pub struct Bytes {
        /// Pointer to the start of this slice (not the allocation).
        ptr: *mut u8,
        /// Length of this slice.
        len: usize,
        /// Shared access to underlying resources.
        ///
        /// Importantly, this is unavailable for as long as the struct exists, which may
        /// prevent shared access to ptr[0 .. len]. I'm not sure I understand Rust's rules
        /// enough to make a strong statement about this.
        sequestered: Rc<Box<Any>>,
    }

    impl Bytes {

        /// Create a new instance from a byte allocation.
        pub fn from<B>(bytes: B) -> Bytes where B: DerefMut<Target=[u8]>+'static {

            let mut boxed = Box::new(bytes) as Box<Any>;

            let ptr = boxed.downcast_mut::<B>().unwrap().as_mut_ptr();
            let len = boxed.downcast_ref::<B>().unwrap().len();
            let sequestered = Rc::new(boxed);

            Bytes {
                ptr,
                len,
                sequestered,
            }
        }

        /// Extracts [0, index) into a new `Bytes` which is returned, updating `self`.
        ///
        /// #Safety
        ///
        /// This method uses an `unsafe` region to advance the pointer by `index`. It first
        /// tests `index` against `self.len`, which should ensure that the offset is in-bounds.
        pub fn extract_to(&mut self, index: usize) -> Bytes {

            assert!(index <= self.len);

            let result = Bytes {
                ptr: self.ptr,
                len: index,
                sequestered: self.sequestered.clone(),
            };

            unsafe { self.ptr = self.ptr.offset(index as isize); }
            self.len -= index;

            result
        }

        /// Recover the underlying storage.
        ///
        /// This method either results in the underlying storage if it is uniquely held, or the
        /// input `Bytes` if it is not uniquely held.
        pub fn try_recover<B>(self) -> Result<B, Bytes> where B: DerefMut<Target=[u8]>+'static {
            match Rc::try_unwrap(self.sequestered) {
                Ok(bytes) => Ok(*bytes.downcast::<B>().unwrap()),
                Err(rc) => Err(Bytes {
                    ptr: self.ptr,
                    len: self.len,
                    sequestered: rc,
                }),
            }
        }
    }

    impl Deref for Bytes {
        type Target = [u8];
        fn deref(&self) -> &[u8] {
            unsafe { ::std::slice::from_raw_parts(self.ptr, self.len) }
        }
    }

    impl DerefMut for Bytes {
        fn deref_mut(&mut self) -> &mut [u8] {
            unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.len) }
        }
    }
}

/// An `Arc`-backed mutable byte slice backed by a common allocation.
pub mod arc {

    use std::ops::{Deref, DerefMut};
    use std::sync::Arc;
    use std::any::Any;

    /// A thread-safe byte buffer backed by a shared allocation.
    pub struct Bytes {
        /// Pointer to the start of this slice (not the allocation).
        ptr: *mut u8,
        /// Length of this slice.
        len: usize,
        /// Shared access to underlying resources.
        ///
        /// Importantly, this is unavailable for as long as the struct exists, which may
        /// prevent shared access to ptr[0 .. len]. I'm not sure I understand Rust's rules
        /// enough to make a strong statement about this.
        sequestered: Arc<Box<Any>>,
    }

    unsafe impl Send for Bytes { }

    impl Bytes {

        /// Create a new instance from a byte allocation.
        pub fn from<B>(bytes: B) -> Bytes where B : DerefMut<Target=[u8]>+'static {

            let mut boxed = Box::new(bytes) as Box<Any>;

            let ptr = boxed.downcast_mut::<B>().unwrap().as_mut_ptr();
            let len = boxed.downcast_ref::<B>().unwrap().len();
            let sequestered = Arc::new(boxed);

            Bytes {
                ptr,
                len,
                sequestered,
            }
        }

        /// Extracts [0, index) into a new `Bytes` which is returned, updating `self`.
        ///
        /// #Safety
        ///
        /// This method uses an `unsafe` region to advance the pointer by `index`. It first
        /// tests `index` against `self.len`, which should ensure that the offset is in-bounds.
        pub fn extract_to(&mut self, index: usize) -> Bytes {

            assert!(index <= self.len);

            let result = Bytes {
                ptr: self.ptr,
                len: index,
                sequestered: self.sequestered.clone(),
            };

            unsafe { self.ptr = self.ptr.offset(index as isize); }
            self.len -= index;

            result
        }

        /// Recover the underlying storage.
        ///
        /// This method either results in the underlying storage if it is uniquely held, or the
        /// input `Bytes` if it is not uniquely held.
        ///
        /// #Examples
        ///
        /// ```
        /// use bytes::arc::Bytes;
        ///
        /// let bytes = vec![0u8; 1024];
        /// let mut shared1 = Bytes::from(bytes);
        /// let mut shared2 = shared1.extract_to(100);
        /// let mut shared3 = shared1.extract_to(100);
        /// let mut shared4 = shared2.extract_to(60);
        ///
        /// drop(shared1);
        /// drop(shared2);
        /// drop(shared4);
        /// let recovered = shared3.try_recover::<Vec<u8>>().ok().expect("recovery failed");
        /// assert!(recovered.len() == 1024);
        /// ```
        pub fn try_recover<B>(self) -> Result<B, Bytes> where B: DerefMut<Target=[u8]>+'static {
            // println!("Trying recovery; strong count: {:?}", Arc::strong_count(&self.sequestered));
            match Arc::try_unwrap(self.sequestered) {
                Ok(bytes) => Ok(*bytes.downcast::<B>().unwrap()),
                Err(arc) => Err(Bytes {
                    ptr: self.ptr,
                    len: self.len,
                    sequestered: arc,
                }),
            }
        }

        /// Regenerates the Bytes if it is uniquely held.
        ///
        /// If uniquely held, this method recovers the initial pointer and length
        /// of the sequestered allocation and re-initialized the Bytes. The return
        /// value indicates whether this occurred.
        ///
        /// #Examples
        ///
        /// ```
        /// use bytes::arc::Bytes;
        ///
        /// let bytes = vec![0u8; 1024];
        /// let mut shared1 = Bytes::from(bytes);
        /// let mut shared2 = shared1.extract_to(100);
        /// let mut shared3 = shared1.extract_to(100);
        /// let mut shared4 = shared2.extract_to(60);
        ///
        /// drop(shared1);
        /// drop(shared2);
        /// drop(shared4);
        /// assert!(shared3.try_regenerate::<Vec<u8>>());
        /// assert!(shared3.len() == 1024);
        /// ```
        pub fn try_regenerate<B>(&mut self) -> bool where B: DerefMut<Target=[u8]>+'static {
            if let Some(boxed) = Arc::get_mut(&mut self.sequestered) {
                let downcast = boxed.downcast_mut::<B>().expect("Downcast failed");
                self.ptr = downcast.as_mut_ptr();
                self.len = downcast.len();
                true
            }
            else {
                false
            }
        }

        /// Attempts to merge adjacent slices from the same allocation.
        ///
        /// If the merge succeeds then `other.len` is added to `self` and the result is `Ok(())`.
        /// If the merge fails self is unmodified and the result is `Err(other)`, returning the
        /// bytes supplied as input.
        ///
        /// #Examples
        ///
        /// ```
        /// use bytes::arc::Bytes;
        ///
        /// let bytes = vec![0u8; 1024];
        /// let mut shared1 = Bytes::from(bytes);
        /// let mut shared2 = shared1.extract_to(100);
        /// let mut shared3 = shared1.extract_to(100);
        /// let mut shared4 = shared2.extract_to(60);
        ///
        /// // memory in slabs [4, 2, 3, 1]: merge back in arbitrary order.
        /// shared2.try_merge(shared3).ok().expect("Failed to merge 2 and 3");
        /// shared2.try_merge(shared1).ok().expect("Failed to merge 23 and 1");
        /// shared4.try_merge(shared2).ok().expect("Failed to merge 4 and 231");
        /// ```
        pub fn try_merge(&mut self, other: Bytes) -> Result<(), Bytes> {
            use ::std::sync::Arc;
            if Arc::ptr_eq(&self.sequestered, &other.sequestered) && ::std::ptr::eq(unsafe { self.ptr.offset(self.len as isize) }, other.ptr) {
                self.len += other.len;
                Ok(())
            }
            else {
                Err(other)
            }
        }
    }

    impl Deref for Bytes {
        type Target = [u8];
        fn deref(&self) -> &[u8] {
            unsafe { ::std::slice::from_raw_parts(self.ptr, self.len) }
        }
    }

    impl DerefMut for Bytes {
        fn deref_mut(&mut self) -> &mut [u8] {
            unsafe { ::std::slice::from_raw_parts_mut(self.ptr, self.len) }
        }
    }
}<|endoftext|>


<commit_before>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::env;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::process;

use proc_macro2::Span;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile(syn::Error),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(e) => write!(f, "Unable to read file: {}", e),
            ParseFile(e) => write!(f, "Unable to parse file: {}", e),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args();
    let _ = args.next(); // executable name

    let filename = match (args.next(), args.next()) {
        (Some(filename), None) => filename,
        _ => return Err(Error::IncorrectUsage),
    };

    let src = fs::read_to_string(filename).map_err(Error::ReadFile)?;

    let syntax = match syn::parse_file(&src) {
        Ok(syntax) => syntax,
        Err(parse_error) => {
            let span = parse_error.span();
            show_location(span, src);
            return Err(Error::ParseFile(parse_error));
        }
    };

    println!("{:#?}", syntax);

    Ok(())
}

fn show_location(span: Span, src: String) {
    let start = span.start();
    let mut end = span.end();

    if start.line == end.line && start.column == end.column {
        return;
    }

    let src_line = match src.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return,
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = src_line.len();
    }

    let underline = " ".repeat(start.column) + &"^".repeat(end.column - start.column);

    let stderr = io::stderr();
    let mut stderr = stderr.lock();
    let _ = writeln!(stderr, "\n{}\n{}\n", src_line, underline);
}
<commit_msg>Format dump-syntax errors in rustc style<commit_after>//! Parse a Rust source file into a `syn::File` and print out a debug
//! representation of the syntax tree.
//!
//! Use the following command from this directory to test this program by
//! running it on its own source code:
//!
//!     cargo run -- main.rs
//!
//! The output will begin with:
//!
//!     File {
//!         shebang: None,
//!         attrs: [
//!             Attribute {
//!                 pound_token: Pound,
//!                 style: Inner(
//!         ...
//!     }

use std::env;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Write};
use std::process;

enum Error {
    IncorrectUsage,
    ReadFile(io::Error),
    ParseFile(syn::Error, String),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
            ReadFile(err) => write!(f, "Unable to read file: {}", err),
            ParseFile(err, code) => render_location(f, err, code),
        }
    }
}

fn main() {
    if let Err(error) = try_main() {
        let _ = writeln!(io::stderr(), "{}", error);
        process::exit(1);
    }
}

fn try_main() -> Result<(), Error> {
    let mut args = env::args();
    let _ = args.next(); // executable name

    let filename = match (args.next(), args.next()) {
        (Some(filename), None) => filename,
        _ => return Err(Error::IncorrectUsage),
    };

    let src = fs::read_to_string(filename).map_err(Error::ReadFile)?;
    let syntax = syn::parse_file(&src).map_err(|parse_error| Error::ParseFile(parse_error, src))?;
    println!("{:#?}", syntax);

    Ok(())
}

fn render_location(formatter: &mut fmt::Formatter, err: &syn::Error, code: &str) -> fmt::Result {
    let start = err.span().start();
    let mut end = err.span().end();

    if start.line == end.line && start.column == end.column {
        return Ok(());
    }

    let code_line = match code.lines().nth(start.line - 1) {
        Some(line) => line,
        None => return Ok(()),
    };

    if end.line > start.line {
        end.line = start.line;
        end.column = code_line.len();
    }

    write!(
        formatter,
        "\n\
         error: Syn unable to parse file\n\
         {indent}--> {filename}:{linenum}:{colnum}\n\
         {indent} | \n\
         {linenum} | {code}\n\
         {indent} | {offset}{underline} {message}\n\
         ",
        filename = "main.rs",
        linenum = start.line,
        colnum = start.column,
        indent = " ".repeat(start.line.to_string().len()),
        code = code_line,
        offset = " ".repeat(start.column),
        underline = "^".repeat(end.column - start.column),
        message = err,
    )
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::collections::HashMap;
use std::sync::Arc;

use crate::config::EndPoint;
use std::net::SocketAddr;

/// Filter is a trait for routing and manipulating packets.
pub trait Filter: Send + Sync {
    /// local_filter filters packets from the local port, and potentially sends them
    /// to configured endpoints.
    /// This function should return the array of endpoints that the packet should be sent to,
    /// and the packet that should be sent (which may be manipulated) as well.
    /// If the packet should be rejected, return None.
    fn local_filter(
        &self,
        endpoints: &Vec<EndPoint>,
        from: SocketAddr,
        contents: Vec<u8>,
    ) -> Option<(Vec<EndPoint>, Vec<u8>)>;

    /// endpoint_filter filters packets received from an endpoint, that is going back to the
    /// original sender.
    /// This function should return the packet to be sent (which may be manipulated).
    /// If the packet should be rejected, return None.
    fn endpoint_filter(&self, endpoint: &EndPoint, contents: Vec<u8>) -> Option<Vec<u8>>;
}

/// FilterRegistry is the registry of all Filters that can be applied in the system.
pub struct FilterRegistry {
    // TODO: remove when used
    #[allow(dead_code)]
    registry: HashMap<String, Arc<dyn Filter>>,
}

impl FilterRegistry {
    pub fn new() -> FilterRegistry {
        FilterRegistry {
            registry: Default::default(),
        }
    }

    /// insert inserts a Filter into the registry.
    // TODO: remove when used
    #[allow(dead_code)]
    pub fn insert(&mut self, key: String, filter: impl Filter + 'static) {
        self.registry.insert(key, Arc::new(filter));
    }

    /// get returns the filter for a given Key. Returns None if not found.
    // TODO: remove when used
    #[allow(dead_code)]
    pub fn get(&self, key: &String) -> Option<&Arc<dyn Filter>> {
        self.registry.get(key)
    }
}

#[cfg(test)]
mod tests {
    use std::net::{IpAddr, Ipv4Addr, SocketAddr};

    use super::*;

    struct TestFilter {}
    impl Filter for TestFilter {
        fn local_filter(
            &self,
            _: &Vec<EndPoint>,
            _: SocketAddr,
            _: Vec<u8>,
        ) -> Option<(Vec<EndPoint>, Vec<u8>)> {
            None
        }
        fn endpoint_filter(&self, _: &EndPoint, _: Vec<u8>) -> Option<Vec<u8>> {
            None
        }
    }

    #[test]
    fn insert_and_get() {
        let mut reg = FilterRegistry::new();
        reg.insert(String::from("test.filter"), TestFilter {});
        assert!(reg.get(&String::from("not.found")).is_none());
        assert!(reg.get(&String::from("test.filter")).is_some());

        let filter = reg.get(&String::from("test.filter")).unwrap();

        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
        let endpoint = EndPoint {
            name: "".to_string(),
            address: addr,
            connection_ids: vec![],
        };

        assert!(filter.local_filter(&vec![], addr, vec![]).is_none());
        assert!(filter.endpoint_filter(&endpoint, vec![]).is_none());
    }
}
<commit_msg>Expand Filter Trait for sending and receiving (#37)<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::collections::HashMap;
use std::sync::Arc;

use crate::config::EndPoint;
use std::net::SocketAddr;

/// Filter is a trait for routing and manipulating packets.
pub trait Filter: Send + Sync {
    /// local_receive_filter receives filters packets from the local port, and potentially sends them
    /// to configured endpoints.
    /// This function should return the array of endpoints that the packet should be sent to,
    /// and the packet that should be sent (which may be manipulated) as well.
    /// If the packet should be rejected, return None.
    fn local_receive_filter(
        &self,
        endpoints: &Vec<EndPoint>,
        from: SocketAddr,
        contents: Vec<u8>,
    ) -> Option<(Vec<EndPoint>, Vec<u8>)>;

    /// local_send_filter intercepts packets that are being sent back to the original local port sender
    /// This function should return the packet to be sent (which may be manipulated).
    /// If the packet should be rejected, return None.
    fn local_send_filter(&self, to: SocketAddr, contents: Vec<u8>) -> Option<Vec<u8>>;

    /// endpoint_receive_filter filters packets received from an endpoint, that is going back to the
    /// original sender.
    /// This function should return the packet to be sent (which may be manipulated).
    /// If the packet should be rejected, return None.
    fn endpoint_receive_filter(&self, endpoint: &EndPoint, contents: Vec<u8>) -> Option<Vec<u8>>;

    /// endpoint_send_filter intercepts packets that are being sent back to the original
    /// endpoint sender address
    /// This function should return the packet to be sent (which may be manipulated).
    /// If the packet should be rejected, return None.
    fn endpoint_send_filter(
        &self,
        endpoint: &EndPoint,
        from: SocketAddr,
        contents: Vec<u8>,
    ) -> Option<Vec<u8>>;
}

/// FilterRegistry is the registry of all Filters that can be applied in the system.
pub struct FilterRegistry {
    // TODO: remove when used
    #[allow(dead_code)]
    registry: HashMap<String, Arc<dyn Filter>>,
}

impl FilterRegistry {
    pub fn new() -> FilterRegistry {
        FilterRegistry {
            registry: Default::default(),
        }
    }

    /// insert inserts a Filter into the registry.
    // TODO: remove when used
    #[allow(dead_code)]
    pub fn insert(&mut self, key: String, filter: impl Filter + 'static) {
        self.registry.insert(key, Arc::new(filter));
    }

    /// get returns the filter for a given Key. Returns None if not found.
    // TODO: remove when used
    #[allow(dead_code)]
    pub fn get(&self, key: &String) -> Option<&Arc<dyn Filter>> {
        self.registry.get(key)
    }
}

#[cfg(test)]
mod tests {
    use std::net::{IpAddr, Ipv4Addr, SocketAddr};

    use super::*;

    struct TestFilter {}

    impl Filter for TestFilter {
        fn local_receive_filter(
            &self,
            _: &Vec<EndPoint>,
            _: SocketAddr,
            _: Vec<u8>,
        ) -> Option<(Vec<EndPoint>, Vec<u8>)> {
            None
        }

        fn local_send_filter(&self, _: SocketAddr, _: Vec<u8>) -> Option<Vec<u8>> {
            None
        }

        fn endpoint_receive_filter(&self, _: &EndPoint, _: Vec<u8>) -> Option<Vec<u8>> {
            None
        }

        fn endpoint_send_filter(&self, _: &EndPoint, _: SocketAddr, _: Vec<u8>) -> Option<Vec<u8>> {
            None
        }
    }

    #[test]
    fn insert_and_get() {
        let mut reg = FilterRegistry::new();
        reg.insert(String::from("test.filter"), TestFilter {});
        assert!(reg.get(&String::from("not.found")).is_none());
        assert!(reg.get(&String::from("test.filter")).is_some());

        let filter = reg.get(&String::from("test.filter")).unwrap();

        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
        let endpoint = EndPoint {
            name: "".to_string(),
            address: addr,
            connection_ids: vec![],
        };

        assert!(filter.local_receive_filter(&vec![], addr, vec![]).is_none());
        assert!(filter.endpoint_receive_filter(&endpoint, vec![]).is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use gst;
use gst::prelude::*;

use std::sync::{Arc, Mutex};
use std::{u32, u64};
use std::collections::VecDeque;

use futures::{Async, Future, IntoFuture, Poll, Stream};
use futures::task;
use futures::sync::oneshot;

use iocontext::*;

lazy_static! {
    static ref DATA_QUEUE_CAT: gst::DebugCategory = gst::DebugCategory::new(
        "ts-dataqueue",
        gst::DebugColorFlags::empty(),
        "Thread-sharing queue",
    );
}

#[derive(Debug)]
pub enum DataQueueItem {
    Buffer(gst::Buffer),
    BufferList(gst::BufferList),
    Event(gst::Event),
}

impl DataQueueItem {
    fn size(&self) -> (u32, u32) {
        match *self {
            DataQueueItem::Buffer(ref buffer) => (1, buffer.get_size() as u32),
            DataQueueItem::BufferList(ref list) => (
                list.len() as u32,
                list.iter().map(|b| b.get_size() as u32).sum::<u32>(),
            ),
            DataQueueItem::Event(_) => (0, 0),
        }
    }

    fn timestamp(&self) -> Option<u64> {
        match *self {
            DataQueueItem::Buffer(ref buffer) => buffer.get_dts_or_pts().0,
            DataQueueItem::BufferList(ref list) => {
                list.iter().filter_map(|b| b.get_dts_or_pts().0).next()
            }
            DataQueueItem::Event(_) => None,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
enum DataQueueState {
    Unscheduled,
    Scheduled,
    Running,
    Shutdown,
}

#[derive(Clone)]
pub struct DataQueue(Arc<Mutex<DataQueueInner>>);

struct DataQueueInner {
    element: gst::Element,

    state: DataQueueState,
    queue: VecDeque<DataQueueItem>,

    cur_size_buffers: u32,
    cur_size_bytes: u32,
    max_size_buffers: Option<u32>,
    max_size_bytes: Option<u32>,
    max_size_time: Option<u64>,

    current_task: Option<task::Task>,
    shutdown_receiver: Option<oneshot::Receiver<()>>,
}

impl DataQueue {
    pub fn new(
        element: &gst::Element,
        max_size_buffers: Option<u32>,
        max_size_bytes: Option<u32>,
        max_size_time: Option<u64>,
    ) -> DataQueue {
        DataQueue(Arc::new(Mutex::new(DataQueueInner {
            element: element.clone(),
            state: DataQueueState::Unscheduled,
            queue: VecDeque::new(),
            cur_size_buffers: 0,
            cur_size_bytes: 0,
            max_size_buffers: max_size_buffers,
            max_size_bytes: max_size_bytes,
            max_size_time: max_size_time,
            current_task: None,
            shutdown_receiver: None,
        })))
    }

    pub fn schedule<U, F, G>(&self, io_context: &IOContext, func: F, err_func: G) -> Result<(), ()>
    where
        F: Fn(DataQueueItem) -> U + Send + 'static,
        U: IntoFuture<Item = (), Error = gst::FlowError> + 'static,
        <U as IntoFuture>::Future: Send + 'static,
        G: FnOnce(gst::FlowError) + Send + 'static,
    {
        // Ready->Paused
        //
        // Need to wait for a possible shutdown to finish first
        // spawn() on the reactor, change state to Scheduled

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Scheduling data queue");
        if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already scheduled");
            return Ok(());
        }

        assert_eq!(inner.state, DataQueueState::Unscheduled);
        inner.state = DataQueueState::Scheduled;

        let (sender, receiver) = oneshot::channel::<()>();
        inner.shutdown_receiver = Some(receiver);

        let queue_clone = self.clone();
        let element_clone = inner.element.clone();
        io_context.spawn(queue_clone.for_each(func).then(move |res| {
            gst_debug!(
                DATA_QUEUE_CAT,
                obj: &element_clone,
                "Data queue finished: {:?}",
                res
            );

            if let Err(err) = res {
                err_func(err);
            }

            let _ = sender.send(());

            Ok(())
        }));
        Ok(())
    }

    pub fn unpause(&self) {
        // Paused->Playing
        //
        // Change state to Running and signal task
        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Unpausing data queue");
        if inner.state == DataQueueState::Running {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already unpaused");
            return;
        }

        assert_eq!(inner.state, DataQueueState::Scheduled);
        inner.state = DataQueueState::Running;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }
    }

    pub fn pause(&self) {
        // Playing->Paused
        //
        // Change state to Scheduled and signal task

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Pausing data queue");
        if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already paused");
            return;
        }

        assert_eq!(inner.state, DataQueueState::Running);
        inner.state = DataQueueState::Scheduled;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }
    }

    pub fn shutdown(&self) {
        // Paused->Ready
        //
        // Change state to Shutdown and signal task, wait for our future to be finished
        // Requires scheduled function to be unblocked! Pad must be deactivated before

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Shutting down data queue");
        if inner.state == DataQueueState::Unscheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already shut down");
            return;
        }

        assert!(inner.state == DataQueueState::Scheduled || inner.state == DataQueueState::Running);
        inner.state = DataQueueState::Shutdown;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }

        let shutdown_receiver = inner.shutdown_receiver.take().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Waiting for data queue to shut down");
        drop(inner);

        shutdown_receiver.wait().expect("Already shut down");

        let mut inner = self.0.lock().unwrap();
        inner.state = DataQueueState::Unscheduled;
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue shut down");
    }

    pub fn clear(&self, src_pad: &gst::Pad) {
        let mut inner = self.0.lock().unwrap();

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Clearing queue");
        for item in inner.queue.drain(..) {
            if let DataQueueItem::Event(event) = item {
                if event.is_sticky() && event.get_type() != gst::EventType::Segment
                    && event.get_type() != gst::EventType::Eos
                {
                    let _ = src_pad.store_sticky_event(&event);
                }
            }
        }
    }

    pub fn push(&self, item: DataQueueItem) -> Result<(), DataQueueItem> {
        let mut inner = self.0.lock().unwrap();

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Pushing item {:?}", item);

        let (count, bytes) = item.size();
        let ts = inner.queue.iter().filter_map(|i| i.timestamp()).next();

        if let Some(max) = inner.max_size_buffers {
            if max <= inner.cur_size_buffers {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (buffers): {} <= {}", max, inner.cur_size_buffers);
                return Err(item);
            }
        }

        if let Some(max) = inner.max_size_bytes {
            if max <= inner.cur_size_bytes {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (bytes): {} <= {}", max, inner.cur_size_bytes);
                return Err(item);
            }
        }

        // FIXME: Use running time
        if let (Some(max), Some(ts)) = (inner.max_size_time, ts) {
            if max <= ts {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (time): {} <= {}", max, ts);
                return Err(item);
            }
        }

        inner.queue.push_back(item);
        inner.cur_size_buffers += count;
        inner.cur_size_bytes += bytes;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }

        Ok(())
    }
}

impl Drop for DataQueueInner {
    fn drop(&mut self) {
        assert_eq!(self.state, DataQueueState::Unscheduled);
    }
}

impl Stream for DataQueue {
    type Item = DataQueueItem;
    type Error = gst::FlowError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut inner = self.0.lock().unwrap();
        if inner.state == DataQueueState::Shutdown {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue shutting down");
            return Ok(Async::Ready(None));
        } else if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue not running");
            inner.current_task = Some(task::current());
            return Ok(Async::NotReady);
        }

        assert_eq!(inner.state, DataQueueState::Running);

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Trying to read data");
        match inner.queue.pop_front() {
            None => {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue is empty");
                inner.current_task = Some(task::current());
                Ok(Async::NotReady)
            }
            Some(item) => {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Popped item {:?}", item);

                let (count, bytes) = item.size();
                inner.cur_size_buffers -= count;
                inner.cur_size_bytes -= bytes;

                Ok(Async::Ready(Some(item)))
            }
        }
    }
}
<commit_msg>threadshare: Fix queue time level calculation<commit_after>// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

use gst;
use gst::prelude::*;

use std::sync::{Arc, Mutex};
use std::{u32, u64};
use std::collections::VecDeque;

use futures::{Async, Future, IntoFuture, Poll, Stream};
use futures::task;
use futures::sync::oneshot;

use iocontext::*;

lazy_static! {
    static ref DATA_QUEUE_CAT: gst::DebugCategory = gst::DebugCategory::new(
        "ts-dataqueue",
        gst::DebugColorFlags::empty(),
        "Thread-sharing queue",
    );
}

#[derive(Debug)]
pub enum DataQueueItem {
    Buffer(gst::Buffer),
    BufferList(gst::BufferList),
    Event(gst::Event),
}

impl DataQueueItem {
    fn size(&self) -> (u32, u32) {
        match *self {
            DataQueueItem::Buffer(ref buffer) => (1, buffer.get_size() as u32),
            DataQueueItem::BufferList(ref list) => (
                list.len() as u32,
                list.iter().map(|b| b.get_size() as u32).sum::<u32>(),
            ),
            DataQueueItem::Event(_) => (0, 0),
        }
    }

    fn timestamp(&self) -> Option<u64> {
        match *self {
            DataQueueItem::Buffer(ref buffer) => buffer.get_dts_or_pts().0,
            DataQueueItem::BufferList(ref list) => {
                list.iter().filter_map(|b| b.get_dts_or_pts().0).next()
            }
            DataQueueItem::Event(_) => None,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
enum DataQueueState {
    Unscheduled,
    Scheduled,
    Running,
    Shutdown,
}

#[derive(Clone)]
pub struct DataQueue(Arc<Mutex<DataQueueInner>>);

struct DataQueueInner {
    element: gst::Element,

    state: DataQueueState,
    queue: VecDeque<DataQueueItem>,

    cur_size_buffers: u32,
    cur_size_bytes: u32,
    max_size_buffers: Option<u32>,
    max_size_bytes: Option<u32>,
    max_size_time: Option<u64>,

    current_task: Option<task::Task>,
    shutdown_receiver: Option<oneshot::Receiver<()>>,
}

impl DataQueue {
    pub fn new(
        element: &gst::Element,
        max_size_buffers: Option<u32>,
        max_size_bytes: Option<u32>,
        max_size_time: Option<u64>,
    ) -> DataQueue {
        DataQueue(Arc::new(Mutex::new(DataQueueInner {
            element: element.clone(),
            state: DataQueueState::Unscheduled,
            queue: VecDeque::new(),
            cur_size_buffers: 0,
            cur_size_bytes: 0,
            max_size_buffers: max_size_buffers,
            max_size_bytes: max_size_bytes,
            max_size_time: max_size_time,
            current_task: None,
            shutdown_receiver: None,
        })))
    }

    pub fn schedule<U, F, G>(&self, io_context: &IOContext, func: F, err_func: G) -> Result<(), ()>
    where
        F: Fn(DataQueueItem) -> U + Send + 'static,
        U: IntoFuture<Item = (), Error = gst::FlowError> + 'static,
        <U as IntoFuture>::Future: Send + 'static,
        G: FnOnce(gst::FlowError) + Send + 'static,
    {
        // Ready->Paused
        //
        // Need to wait for a possible shutdown to finish first
        // spawn() on the reactor, change state to Scheduled

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Scheduling data queue");
        if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already scheduled");
            return Ok(());
        }

        assert_eq!(inner.state, DataQueueState::Unscheduled);
        inner.state = DataQueueState::Scheduled;

        let (sender, receiver) = oneshot::channel::<()>();
        inner.shutdown_receiver = Some(receiver);

        let queue_clone = self.clone();
        let element_clone = inner.element.clone();
        io_context.spawn(queue_clone.for_each(func).then(move |res| {
            gst_debug!(
                DATA_QUEUE_CAT,
                obj: &element_clone,
                "Data queue finished: {:?}",
                res
            );

            if let Err(err) = res {
                err_func(err);
            }

            let _ = sender.send(());

            Ok(())
        }));
        Ok(())
    }

    pub fn unpause(&self) {
        // Paused->Playing
        //
        // Change state to Running and signal task
        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Unpausing data queue");
        if inner.state == DataQueueState::Running {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already unpaused");
            return;
        }

        assert_eq!(inner.state, DataQueueState::Scheduled);
        inner.state = DataQueueState::Running;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }
    }

    pub fn pause(&self) {
        // Playing->Paused
        //
        // Change state to Scheduled and signal task

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Pausing data queue");
        if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already paused");
            return;
        }

        assert_eq!(inner.state, DataQueueState::Running);
        inner.state = DataQueueState::Scheduled;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }
    }

    pub fn shutdown(&self) {
        // Paused->Ready
        //
        // Change state to Shutdown and signal task, wait for our future to be finished
        // Requires scheduled function to be unblocked! Pad must be deactivated before

        let mut inner = self.0.lock().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Shutting down data queue");
        if inner.state == DataQueueState::Unscheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue already shut down");
            return;
        }

        assert!(inner.state == DataQueueState::Scheduled || inner.state == DataQueueState::Running);
        inner.state = DataQueueState::Shutdown;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }

        let shutdown_receiver = inner.shutdown_receiver.take().unwrap();
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Waiting for data queue to shut down");
        drop(inner);

        shutdown_receiver.wait().expect("Already shut down");

        let mut inner = self.0.lock().unwrap();
        inner.state = DataQueueState::Unscheduled;
        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue shut down");
    }

    pub fn clear(&self, src_pad: &gst::Pad) {
        let mut inner = self.0.lock().unwrap();

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Clearing queue");
        for item in inner.queue.drain(..) {
            if let DataQueueItem::Event(event) = item {
                if event.is_sticky() && event.get_type() != gst::EventType::Segment
                    && event.get_type() != gst::EventType::Eos
                {
                    let _ = src_pad.store_sticky_event(&event);
                }
            }
        }
    }

    pub fn push(&self, item: DataQueueItem) -> Result<(), DataQueueItem> {
        let mut inner = self.0.lock().unwrap();

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Pushing item {:?}", item);

        let (count, bytes) = item.size();
        let queue_ts = inner.queue.iter().filter_map(|i| i.timestamp()).next();
        let ts = item.timestamp();

        if let Some(max) = inner.max_size_buffers {
            if max <= inner.cur_size_buffers {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (buffers): {} <= {}", max, inner.cur_size_buffers);
                return Err(item);
            }
        }

        if let Some(max) = inner.max_size_bytes {
            if max <= inner.cur_size_bytes {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (bytes): {} <= {}", max, inner.cur_size_bytes);
                return Err(item);
            }
        }

        // FIXME: Use running time
        if let (Some(max), Some(queue_ts), Some(ts)) = (inner.max_size_time, queue_ts, ts) {
            let level = if queue_ts > ts {
                queue_ts - ts
            } else {
                ts - queue_ts
            };

            if max <= level {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Queue is full (time): {} <= {}", max, level);
                return Err(item);
            }
        }

        inner.queue.push_back(item);
        inner.cur_size_buffers += count;
        inner.cur_size_bytes += bytes;

        if let Some(task) = inner.current_task.take() {
            task.notify();
        }

        Ok(())
    }
}

impl Drop for DataQueueInner {
    fn drop(&mut self) {
        assert_eq!(self.state, DataQueueState::Unscheduled);
    }
}

impl Stream for DataQueue {
    type Item = DataQueueItem;
    type Error = gst::FlowError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut inner = self.0.lock().unwrap();
        if inner.state == DataQueueState::Shutdown {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue shutting down");
            return Ok(Async::Ready(None));
        } else if inner.state == DataQueueState::Scheduled {
            gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue not running");
            inner.current_task = Some(task::current());
            return Ok(Async::NotReady);
        }

        assert_eq!(inner.state, DataQueueState::Running);

        gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Trying to read data");
        match inner.queue.pop_front() {
            None => {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Data queue is empty");
                inner.current_task = Some(task::current());
                Ok(Async::NotReady)
            }
            Some(item) => {
                gst_debug!(DATA_QUEUE_CAT, obj: &inner.element, "Popped item {:?}", item);

                let (count, bytes) = item.size();
                inner.cur_size_buffers -= count;
                inner.cur_size_bytes -= bytes;

                Ok(Async::Ready(Some(item)))
            }
        }
    }
}
<|endoftext|>