<commit_before>use crate::types::{GossipEncoding, GossipKind, GossipTopic};
use crate::{error, TopicHash};
use libp2p::gossipsub::{
    GossipsubConfig, IdentTopic as Topic, PeerScoreParams, PeerScoreThresholds, TopicScoreParams,
};
use std::cmp::max;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::time::Duration;
use types::{ChainSpec, EnrForkId, EthSpec, Slot, SubnetId};

const MAX_IN_MESH_SCORE: f64 = 10.0;
const MAX_FIRST_MESSAGE_DELIVERIES_SCORE: f64 = 40.0;
const BEACON_BLOCK_WEIGHT: f64 = 0.5;
const BEACON_AGGREGATE_PROOF_WEIGHT: f64 = 0.5;
const VOLUNTARY_EXIT_WEIGHT: f64 = 0.05;
const PROPOSER_SLASHING_WEIGHT: f64 = 0.05;
const ATTESTER_SLASHING_WEIGHT: f64 = 0.05;

pub struct PeerScoreSettings<TSpec: EthSpec> {
    slot: Duration,
    epoch: Duration,

    beacon_attestation_subnet_weight: f64,
    max_positive_score: f64,

    decay_interval: Duration,
    decay_to_zero: f64,

    mesh_n: usize,
    max_committees_per_slot: usize,
    target_committee_size: usize,
    target_aggregators_per_committee: usize,
    attestation_subnet_count: u64,
    phantom: PhantomData<TSpec>,
}

impl<TSpec: EthSpec> PeerScoreSettings<TSpec> {
    pub fn new(chain_spec: &ChainSpec, gs_config: &GossipsubConfig) -> PeerScoreSettings<TSpec> {
        let slot = Duration::from_millis(chain_spec.seconds_per_slot);
        let beacon_attestation_subnet_weight = 1.0 / chain_spec.attestation_subnet_count as f64;
        let max_positive_score = (MAX_IN_MESH_SCORE + MAX_FIRST_MESSAGE_DELIVERIES_SCORE)
            * (BEACON_BLOCK_WEIGHT
                + BEACON_AGGREGATE_PROOF_WEIGHT
                + beacon_attestation_subnet_weight * chain_spec.attestation_subnet_count as f64
                + VOLUNTARY_EXIT_WEIGHT
                + PROPOSER_SLASHING_WEIGHT
                + ATTESTER_SLASHING_WEIGHT);

        PeerScoreSettings {
            slot,
            epoch: slot * TSpec::slots_per_epoch() as u32,
            beacon_attestation_subnet_weight,
            max_positive_score,
            decay_interval: max(Duration::from_secs(1), slot),
            decay_to_zero: 0.01,
            mesh_n: gs_config.mesh_n(),
            max_committees_per_slot: chain_spec.max_committees_per_slot,
            target_committee_size: chain_spec.target_committee_size,
            target_aggregators_per_committee: chain_spec.target_aggregators_per_committee as usize,
            attestation_subnet_count: chain_spec.attestation_subnet_count,
            phantom: PhantomData,
        }
    }

    pub fn get_peer_score_params(
        &self,
        active_validators: usize,
        thresholds: &PeerScoreThresholds,
        enr_fork_id: &EnrForkId,
        current_slot: Slot,
    ) -> error::Result<PeerScoreParams> {
        let mut params = PeerScoreParams {
            decay_interval: self.decay_interval,
            decay_to_zero: self.decay_to_zero,
            retain_score: self.epoch * 100,
            app_specific_weight: 1.0,
            ip_colocation_factor_threshold: 3.0,
            behaviour_penalty_threshold: 6.0,
            behaviour_penalty_decay: self.score_parameter_decay(self.epoch * 10),
            ..Default::default()
        };

        let target_value = Self::decay_convergence(
            params.behaviour_penalty_decay,
            10.0 / TSpec::slots_per_epoch() as f64,
        ) - params.behaviour_penalty_threshold;
        params.behaviour_penalty_weight = thresholds.gossip_threshold / target_value.powi(2);

        params.topic_score_cap = self.max_positive_score * 0.5;
        params.ip_colocation_factor_weight = -params.topic_score_cap;

        params.topics = HashMap::new();

        let get_hash = |kind: GossipKind| -> TopicHash {
            let topic: Topic =
                GossipTopic::new(kind, GossipEncoding::default(), enr_fork_id.fork_digest).into();
            topic.hash()
        };

        //first all fixed topics
        params.topics.insert(
            get_hash(GossipKind::VoluntaryExit),
            Self::get_topic_params(
                self,
                VOLUNTARY_EXIT_WEIGHT,
                4.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );
        params.topics.insert(
            get_hash(GossipKind::AttesterSlashing),
            Self::get_topic_params(
                self,
                ATTESTER_SLASHING_WEIGHT,
                1.0 / 5.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );
        params.topics.insert(
            get_hash(GossipKind::ProposerSlashing),
            Self::get_topic_params(
                self,
                PROPOSER_SLASHING_WEIGHT,
                1.0 / 5.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );

        //dynamic topics
        let (beacon_block_params, beacon_aggregate_proof_params, beacon_attestation_subnet_params) =
            self.get_dynamic_topic_params(active_validators, current_slot)?;

        params
            .topics
            .insert(get_hash(GossipKind::BeaconBlock), beacon_block_params);

        params.topics.insert(
            get_hash(GossipKind::BeaconAggregateAndProof),
            beacon_aggregate_proof_params,
        );

        for i in 0..self.attestation_subnet_count {
            params.topics.insert(
                get_hash(GossipKind::Attestation(SubnetId::new(i))),
                beacon_attestation_subnet_params.clone(),
            );
        }

        Ok(params)
    }

    pub fn get_dynamic_topic_params(
        &self,
        active_validators: usize,
        current_slot: Slot,
    ) -> error::Result<(TopicScoreParams, TopicScoreParams, TopicScoreParams)> {
        let (aggregators_per_slot, committees_per_slot) =
            self.expected_aggregator_count_per_slot(active_validators)?;
        let multiple_bursts_per_subnet_per_epoch = committees_per_slot as u64
            >= 2 * self.attestation_subnet_count / TSpec::slots_per_epoch();

        let beacon_block_params = Self::get_topic_params(
            self,
            BEACON_BLOCK_WEIGHT,
            1.0,
            self.epoch * 20,
            Some((TSpec::slots_per_epoch() * 5, 3.0, self.epoch, current_slot)),
        );

        let beacon_aggregate_proof_params = Self::get_topic_params(
            self,
            BEACON_AGGREGATE_PROOF_WEIGHT,
            aggregators_per_slot,
            self.epoch,
            Some((TSpec::slots_per_epoch() * 2, 4.0, self.epoch, current_slot)),
        );
        let beacon_attestation_subnet_params = Self::get_topic_params(
            self,
            self.beacon_attestation_subnet_weight,
            active_validators as f64
                / self.attestation_subnet_count as f64
                / TSpec::slots_per_epoch() as f64,
            self.epoch
                * (if multiple_bursts_per_subnet_per_epoch {
                    1
                } else {
                    4
                }),
            Some((
                TSpec::slots_per_epoch()
                    * (if multiple_bursts_per_subnet_per_epoch {
                        4
                    } else {
                        16
                    }),
                16.0,
                if multiple_bursts_per_subnet_per_epoch {
                    self.slot * (TSpec::slots_per_epoch() as u32 / 2 + 1)
                } else {
                    self.epoch * 3
                },
                current_slot,
            )),
        );

        Ok((
            beacon_block_params,
            beacon_aggregate_proof_params,
            beacon_attestation_subnet_params,
        ))
    }

    pub fn attestation_subnet_count(&self) -> u64 {
        self.attestation_subnet_count
    }

    fn score_parameter_decay_with_base(
        decay_time: Duration,
        decay_interval: Duration,
        decay_to_zero: f64,
    ) -> f64 {
        let ticks = decay_time.as_secs_f64() / decay_interval.as_secs_f64();
        decay_to_zero.powf(1.0 / ticks)
    }

    fn decay_convergence(decay: f64, rate: f64) -> f64 {
        rate / (1.0 - decay)
    }

    fn threshold(decay: f64, rate: f64) -> f64 {
        Self::decay_convergence(decay, rate) * decay
    }

    fn expected_aggregator_count_per_slot(
        &self,
        active_validators: usize,
    ) -> error::Result<(f64, usize)> {
        let committees_per_slot = TSpec::get_committee_count_per_slot_with(
            active_validators,
            self.max_committees_per_slot,
            self.target_committee_size,
        )
        .map_err(|e| format!("Could not get committee count from spec: {:?}", e))?;

        let committees = committees_per_slot * TSpec::slots_per_epoch() as usize;

        let smaller_committee_size = active_validators / committees;
        let num_larger_committees = active_validators - smaller_committee_size * committees;

        let modulo_smaller = max(
            1,
            smaller_committee_size / self.target_aggregators_per_committee as usize,
        );
        let modulo_larger = max(
            1,
            (smaller_committee_size + 1) / self.target_aggregators_per_committee as usize,
        );

        Ok((
            (((committees - num_larger_committees) * smaller_committee_size) as f64
                / modulo_smaller as f64
                + (num_larger_committees * (smaller_committee_size + 1)) as f64
                    / modulo_larger as f64)
                / TSpec::slots_per_epoch() as f64,
            committees_per_slot,
        ))
    }

    fn score_parameter_decay(&self, decay_time: Duration) -> f64 {
        Self::score_parameter_decay_with_base(decay_time, self.decay_interval, self.decay_to_zero)
    }

    fn get_topic_params(
        &self,
        topic_weight: f64,
        expected_message_rate: f64,
        first_message_decay_time: Duration,
        // decay slots (decay time in slots), cap factor, activation window, current slot
        mesh_message_info: Option<(u64, f64, Duration, Slot)>,
    ) -> TopicScoreParams {
        let mut t_params = TopicScoreParams::default();

        t_params.topic_weight = topic_weight;

        t_params.time_in_mesh_quantum = self.slot;
        t_params.time_in_mesh_cap = 3600.0 / t_params.time_in_mesh_quantum.as_secs_f64();
        t_params.time_in_mesh_weight = 10.0 / t_params.time_in_mesh_cap;

        t_params.first_message_deliveries_decay =
            self.score_parameter_decay(first_message_decay_time);
        t_params.first_message_deliveries_cap = Self::decay_convergence(
            t_params.first_message_deliveries_decay,
            2.0 * expected_message_rate / self.mesh_n as f64,
        );
        t_params.first_message_deliveries_weight = 40.0 / t_params.first_message_deliveries_cap;

        if let Some((decay_slots, cap_factor, activation_window, current_slot)) = mesh_message_info
        {
            let decay_time = self.slot * decay_slots as u32;
            t_params.mesh_message_deliveries_decay = self.score_parameter_decay(decay_time);
            t_params.mesh_message_deliveries_threshold = Self::threshold(
                t_params.mesh_message_deliveries_decay,
                expected_message_rate / 50.0,
            );
            t_params.mesh_message_deliveries_cap =
                if cap_factor * t_params.mesh_message_deliveries_threshold < 2.0 {
                    2.0
                } else {
                    cap_factor * t_params.mesh_message_deliveries_threshold
                };
            t_params.mesh_message_deliveries_activation = activation_window;
            t_params.mesh_message_deliveries_window = Duration::from_secs(2);
            t_params.mesh_failure_penalty_decay = t_params.mesh_message_deliveries_decay;
            t_params.mesh_message_deliveries_weight = -self.max_positive_score
                / (t_params.topic_weight * t_params.mesh_message_deliveries_threshold.powi(2));
            t_params.mesh_failure_penalty_weight = t_params.mesh_message_deliveries_weight;
            if decay_slots >= current_slot.as_u64() {
                t_params.mesh_message_deliveries_threshold = 0.0;
                t_params.mesh_message_deliveries_weight = 0.0;
            }
        } else {
            t_params.mesh_message_deliveries_weight = 0.0;
            t_params.mesh_message_deliveries_threshold = 0.0;
            t_params.mesh_message_deliveries_decay = 0.0;
            t_params.mesh_message_deliveries_cap = 0.0;
            t_params.mesh_message_deliveries_window = Duration::from_secs(0);
            t_params.mesh_message_deliveries_activation = Duration::from_secs(0);
            t_params.mesh_failure_penalty_decay = 0.0;
            t_params.mesh_failure_penalty_weight = 0.0;
        }

        t_params.invalid_message_deliveries_weight =
            -self.max_positive_score / t_params.topic_weight;
        t_params.invalid_message_deliveries_decay = self.score_parameter_decay(self.epoch * 50);

        t_params
    }
}
<commit_msg>Fix bug from #2163 (#2165)<commit_after>use crate::types::{GossipEncoding, GossipKind, GossipTopic};
use crate::{error, TopicHash};
use libp2p::gossipsub::{
    GossipsubConfig, IdentTopic as Topic, PeerScoreParams, PeerScoreThresholds, TopicScoreParams,
};
use std::cmp::max;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::time::Duration;
use types::{ChainSpec, EnrForkId, EthSpec, Slot, SubnetId};

const MAX_IN_MESH_SCORE: f64 = 10.0;
const MAX_FIRST_MESSAGE_DELIVERIES_SCORE: f64 = 40.0;
const BEACON_BLOCK_WEIGHT: f64 = 0.5;
const BEACON_AGGREGATE_PROOF_WEIGHT: f64 = 0.5;
const VOLUNTARY_EXIT_WEIGHT: f64 = 0.05;
const PROPOSER_SLASHING_WEIGHT: f64 = 0.05;
const ATTESTER_SLASHING_WEIGHT: f64 = 0.05;

pub struct PeerScoreSettings<TSpec: EthSpec> {
    slot: Duration,
    epoch: Duration,

    beacon_attestation_subnet_weight: f64,
    max_positive_score: f64,

    decay_interval: Duration,
    decay_to_zero: f64,

    mesh_n: usize,
    max_committees_per_slot: usize,
    target_committee_size: usize,
    target_aggregators_per_committee: usize,
    attestation_subnet_count: u64,
    phantom: PhantomData<TSpec>,
}

impl<TSpec: EthSpec> PeerScoreSettings<TSpec> {
    pub fn new(chain_spec: &ChainSpec, gs_config: &GossipsubConfig) -> PeerScoreSettings<TSpec> {
        let slot = Duration::from_secs(chain_spec.seconds_per_slot);
        let beacon_attestation_subnet_weight = 1.0 / chain_spec.attestation_subnet_count as f64;
        let max_positive_score = (MAX_IN_MESH_SCORE + MAX_FIRST_MESSAGE_DELIVERIES_SCORE)
            * (BEACON_BLOCK_WEIGHT
                + BEACON_AGGREGATE_PROOF_WEIGHT
                + beacon_attestation_subnet_weight * chain_spec.attestation_subnet_count as f64
                + VOLUNTARY_EXIT_WEIGHT
                + PROPOSER_SLASHING_WEIGHT
                + ATTESTER_SLASHING_WEIGHT);

        PeerScoreSettings {
            slot,
            epoch: slot * TSpec::slots_per_epoch() as u32,
            beacon_attestation_subnet_weight,
            max_positive_score,
            decay_interval: max(Duration::from_secs(1), slot),
            decay_to_zero: 0.01,
            mesh_n: gs_config.mesh_n(),
            max_committees_per_slot: chain_spec.max_committees_per_slot,
            target_committee_size: chain_spec.target_committee_size,
            target_aggregators_per_committee: chain_spec.target_aggregators_per_committee as usize,
            attestation_subnet_count: chain_spec.attestation_subnet_count,
            phantom: PhantomData,
        }
    }

    pub fn get_peer_score_params(
        &self,
        active_validators: usize,
        thresholds: &PeerScoreThresholds,
        enr_fork_id: &EnrForkId,
        current_slot: Slot,
    ) -> error::Result<PeerScoreParams> {
        let mut params = PeerScoreParams {
            decay_interval: self.decay_interval,
            decay_to_zero: self.decay_to_zero,
            retain_score: self.epoch * 100,
            app_specific_weight: 1.0,
            ip_colocation_factor_threshold: 3.0,
            behaviour_penalty_threshold: 6.0,
            behaviour_penalty_decay: self.score_parameter_decay(self.epoch * 10),
            ..Default::default()
        };

        let target_value = Self::decay_convergence(
            params.behaviour_penalty_decay,
            10.0 / TSpec::slots_per_epoch() as f64,
        ) - params.behaviour_penalty_threshold;
        params.behaviour_penalty_weight = thresholds.gossip_threshold / target_value.powi(2);

        params.topic_score_cap = self.max_positive_score * 0.5;
        params.ip_colocation_factor_weight = -params.topic_score_cap;

        params.topics = HashMap::new();

        let get_hash = |kind: GossipKind| -> TopicHash {
            let topic: Topic =
                GossipTopic::new(kind, GossipEncoding::default(), enr_fork_id.fork_digest).into();
            topic.hash()
        };

        //first all fixed topics
        params.topics.insert(
            get_hash(GossipKind::VoluntaryExit),
            Self::get_topic_params(
                self,
                VOLUNTARY_EXIT_WEIGHT,
                4.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );
        params.topics.insert(
            get_hash(GossipKind::AttesterSlashing),
            Self::get_topic_params(
                self,
                ATTESTER_SLASHING_WEIGHT,
                1.0 / 5.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );
        params.topics.insert(
            get_hash(GossipKind::ProposerSlashing),
            Self::get_topic_params(
                self,
                PROPOSER_SLASHING_WEIGHT,
                1.0 / 5.0 / TSpec::slots_per_epoch() as f64,
                self.epoch * 100,
                None,
            ),
        );

        //dynamic topics
        let (beacon_block_params, beacon_aggregate_proof_params, beacon_attestation_subnet_params) =
            self.get_dynamic_topic_params(active_validators, current_slot)?;

        params
            .topics
            .insert(get_hash(GossipKind::BeaconBlock), beacon_block_params);

        params.topics.insert(
            get_hash(GossipKind::BeaconAggregateAndProof),
            beacon_aggregate_proof_params,
        );

        for i in 0..self.attestation_subnet_count {
            params.topics.insert(
                get_hash(GossipKind::Attestation(SubnetId::new(i))),
                beacon_attestation_subnet_params.clone(),
            );
        }

        Ok(params)
    }

    pub fn get_dynamic_topic_params(
        &self,
        active_validators: usize,
        current_slot: Slot,
    ) -> error::Result<(TopicScoreParams, TopicScoreParams, TopicScoreParams)> {
        let (aggregators_per_slot, committees_per_slot) =
            self.expected_aggregator_count_per_slot(active_validators)?;
        let multiple_bursts_per_subnet_per_epoch = committees_per_slot as u64
            >= 2 * self.attestation_subnet_count / TSpec::slots_per_epoch();

        let beacon_block_params = Self::get_topic_params(
            self,
            BEACON_BLOCK_WEIGHT,
            1.0,
            self.epoch * 20,
            Some((TSpec::slots_per_epoch() * 5, 3.0, self.epoch, current_slot)),
        );

        let beacon_aggregate_proof_params = Self::get_topic_params(
            self,
            BEACON_AGGREGATE_PROOF_WEIGHT,
            aggregators_per_slot,
            self.epoch,
            Some((TSpec::slots_per_epoch() * 2, 4.0, self.epoch, current_slot)),
        );
        let beacon_attestation_subnet_params = Self::get_topic_params(
            self,
            self.beacon_attestation_subnet_weight,
            active_validators as f64
                / self.attestation_subnet_count as f64
                / TSpec::slots_per_epoch() as f64,
            self.epoch
                * (if multiple_bursts_per_subnet_per_epoch {
                    1
                } else {
                    4
                }),
            Some((
                TSpec::slots_per_epoch()
                    * (if multiple_bursts_per_subnet_per_epoch {
                        4
                    } else {
                        16
                    }),
                16.0,
                if multiple_bursts_per_subnet_per_epoch {
                    self.slot * (TSpec::slots_per_epoch() as u32 / 2 + 1)
                } else {
                    self.epoch * 3
                },
                current_slot,
            )),
        );

        Ok((
            beacon_block_params,
            beacon_aggregate_proof_params,
            beacon_attestation_subnet_params,
        ))
    }

    pub fn attestation_subnet_count(&self) -> u64 {
        self.attestation_subnet_count
    }

    fn score_parameter_decay_with_base(
        decay_time: Duration,
        decay_interval: Duration,
        decay_to_zero: f64,
    ) -> f64 {
        let ticks = decay_time.as_secs_f64() / decay_interval.as_secs_f64();
        decay_to_zero.powf(1.0 / ticks)
    }

    fn decay_convergence(decay: f64, rate: f64) -> f64 {
        rate / (1.0 - decay)
    }

    fn threshold(decay: f64, rate: f64) -> f64 {
        Self::decay_convergence(decay, rate) * decay
    }

    fn expected_aggregator_count_per_slot(
        &self,
        active_validators: usize,
    ) -> error::Result<(f64, usize)> {
        let committees_per_slot = TSpec::get_committee_count_per_slot_with(
            active_validators,
            self.max_committees_per_slot,
            self.target_committee_size,
        )
        .map_err(|e| format!("Could not get committee count from spec: {:?}", e))?;

        let committees = committees_per_slot * TSpec::slots_per_epoch() as usize;

        let smaller_committee_size = active_validators / committees;
        let num_larger_committees = active_validators - smaller_committee_size * committees;

        let modulo_smaller = max(
            1,
            smaller_committee_size / self.target_aggregators_per_committee as usize,
        );
        let modulo_larger = max(
            1,
            (smaller_committee_size + 1) / self.target_aggregators_per_committee as usize,
        );

        Ok((
            (((committees - num_larger_committees) * smaller_committee_size) as f64
                / modulo_smaller as f64
                + (num_larger_committees * (smaller_committee_size + 1)) as f64
                    / modulo_larger as f64)
                / TSpec::slots_per_epoch() as f64,
            committees_per_slot,
        ))
    }

    fn score_parameter_decay(&self, decay_time: Duration) -> f64 {
        Self::score_parameter_decay_with_base(decay_time, self.decay_interval, self.decay_to_zero)
    }

    fn get_topic_params(
        &self,
        topic_weight: f64,
        expected_message_rate: f64,
        first_message_decay_time: Duration,
        // decay slots (decay time in slots), cap factor, activation window, current slot
        mesh_message_info: Option<(u64, f64, Duration, Slot)>,
    ) -> TopicScoreParams {
        let mut t_params = TopicScoreParams::default();

        t_params.topic_weight = topic_weight;

        t_params.time_in_mesh_quantum = self.slot;
        t_params.time_in_mesh_cap = 3600.0 / t_params.time_in_mesh_quantum.as_secs_f64();
        t_params.time_in_mesh_weight = 10.0 / t_params.time_in_mesh_cap;

        t_params.first_message_deliveries_decay =
            self.score_parameter_decay(first_message_decay_time);
        t_params.first_message_deliveries_cap = Self::decay_convergence(
            t_params.first_message_deliveries_decay,
            2.0 * expected_message_rate / self.mesh_n as f64,
        );
        t_params.first_message_deliveries_weight = 40.0 / t_params.first_message_deliveries_cap;

        if let Some((decay_slots, cap_factor, activation_window, current_slot)) = mesh_message_info
        {
            let decay_time = self.slot * decay_slots as u32;
            t_params.mesh_message_deliveries_decay = self.score_parameter_decay(decay_time);
            t_params.mesh_message_deliveries_threshold = Self::threshold(
                t_params.mesh_message_deliveries_decay,
                expected_message_rate / 50.0,
            );
            t_params.mesh_message_deliveries_cap =
                if cap_factor * t_params.mesh_message_deliveries_threshold < 2.0 {
                    2.0
                } else {
                    cap_factor * t_params.mesh_message_deliveries_threshold
                };
            t_params.mesh_message_deliveries_activation = activation_window;
            t_params.mesh_message_deliveries_window = Duration::from_secs(2);
            t_params.mesh_failure_penalty_decay = t_params.mesh_message_deliveries_decay;
            t_params.mesh_message_deliveries_weight = -self.max_positive_score
                / (t_params.topic_weight * t_params.mesh_message_deliveries_threshold.powi(2));
            t_params.mesh_failure_penalty_weight = t_params.mesh_message_deliveries_weight;
            if decay_slots >= current_slot.as_u64() {
                t_params.mesh_message_deliveries_threshold = 0.0;
                t_params.mesh_message_deliveries_weight = 0.0;
            }
        } else {
            t_params.mesh_message_deliveries_weight = 0.0;
            t_params.mesh_message_deliveries_threshold = 0.0;
            t_params.mesh_message_deliveries_decay = 0.0;
            t_params.mesh_message_deliveries_cap = 0.0;
            t_params.mesh_message_deliveries_window = Duration::from_secs(0);
            t_params.mesh_message_deliveries_activation = Duration::from_secs(0);
            t_params.mesh_failure_penalty_decay = 0.0;
            t_params.mesh_failure_penalty_weight = 0.0;
        }

        t_params.invalid_message_deliveries_weight =
            -self.max_positive_score / t_params.topic_weight;
        t_params.invalid_message_deliveries_decay = self.score_parameter_decay(self.epoch * 50);

        t_params
    }
}
<|endoftext|>


<commit_before>use client_died_error_holder::ClientConnDiedType;
use client_died_error_holder::ClientDiedErrorHolder;
use common::conn_command_channel::ConnCommandSender;
use common::increase_in_window::IncreaseInWindow;
use common::stream_from_network::StreamFromNetwork;
use common::stream_queue_sync::stream_queue_sync;
use server::increase_in_window::ServerIncreaseInWindow;
use server::stream_handler::ServerStreamHandler;
use server::stream_handler::ServerStreamHandlerHolder;
use server::types::ServerTypes;
use Headers;
use HttpStreamAfterHeaders;
use StreamId;

pub struct ServerRequest<'a> {
    /// Request headers
    pub headers: Headers,
    /// True if requests ends with headers
    pub end_stream: bool,
    pub(crate) stream_id: StreamId,
    /// Stream in window size at the moment of request start
    pub(crate) in_window_size: u32,
    pub(crate) stream_handler: &'a mut Option<ServerStreamHandlerHolder>,
    pub(crate) conn_died_error_holder: &'a ClientDiedErrorHolder<ClientConnDiedType>,
    pub(crate) to_write_tx: &'a ConnCommandSender<ServerTypes>,
}

impl<'a> ServerRequest<'a> {
    pub fn make_stream(&mut self) -> HttpStreamAfterHeaders {
        if self.end_stream {
            HttpStreamAfterHeaders::empty()
        } else {
            let client_died_error_holder = self.conn_died_error_holder.clone();
            let in_window_size = self.in_window_size;
            self.register_stream_handler(|increase_in_window| {
                let (inc_tx, inc_rx) = stream_queue_sync(client_died_error_holder);
                let stream_from_network = StreamFromNetwork {
                    rx: inc_rx,
                    increase_in_window: increase_in_window.0,
                    in_window_size,
                };

                (
                    inc_tx,
                    HttpStreamAfterHeaders::from_parts(stream_from_network),
                )
            })
        }
    }

    pub fn register_stream_handler<F, H, R>(&mut self, f: F) -> R
    where
        F: FnOnce(ServerIncreaseInWindow) -> (H, R),
        H: ServerStreamHandler,
    {
        assert!(self.stream_handler.is_none());
        let increase_window = ServerIncreaseInWindow(IncreaseInWindow {
            stream_id: self.stream_id,
            to_write_tx: self.to_write_tx.clone(),
        });
        let (h, r) = f(increase_window);
        *self.stream_handler = Some(ServerStreamHandlerHolder(Box::new(h)));
        r
    }
}
<commit_msg>Supply current window size to register_stream_handler callback<commit_after>use client_died_error_holder::ClientConnDiedType;
use client_died_error_holder::ClientDiedErrorHolder;
use common::conn_command_channel::ConnCommandSender;
use common::increase_in_window::IncreaseInWindow;
use common::stream_from_network::StreamFromNetwork;
use common::stream_queue_sync::stream_queue_sync;
use server::increase_in_window::ServerIncreaseInWindow;
use server::stream_handler::ServerStreamHandler;
use server::stream_handler::ServerStreamHandlerHolder;
use server::types::ServerTypes;
use Headers;
use HttpStreamAfterHeaders;
use StreamId;

pub struct ServerRequest<'a> {
    /// Request headers
    pub headers: Headers,
    /// True if requests ends with headers
    pub end_stream: bool,
    pub(crate) stream_id: StreamId,
    /// Stream in window size at the moment of request start
    pub(crate) in_window_size: u32,
    pub(crate) stream_handler: &'a mut Option<ServerStreamHandlerHolder>,
    pub(crate) conn_died_error_holder: &'a ClientDiedErrorHolder<ClientConnDiedType>,
    pub(crate) to_write_tx: &'a ConnCommandSender<ServerTypes>,
}

impl<'a> ServerRequest<'a> {
    pub fn make_stream(&mut self) -> HttpStreamAfterHeaders {
        if self.end_stream {
            HttpStreamAfterHeaders::empty()
        } else {
            let client_died_error_holder = self.conn_died_error_holder.clone();
            self.register_stream_handler(|increase_in_window, in_window_size| {
                let (inc_tx, inc_rx) = stream_queue_sync(client_died_error_holder);
                let stream_from_network = StreamFromNetwork {
                    rx: inc_rx,
                    increase_in_window: increase_in_window.0,
                    in_window_size,
                };

                (
                    inc_tx,
                    HttpStreamAfterHeaders::from_parts(stream_from_network),
                )
            })
        }
    }

    pub fn register_stream_handler<F, H, R>(&mut self, f: F) -> R
    where
        F: FnOnce(ServerIncreaseInWindow, u32) -> (H, R),
        H: ServerStreamHandler,
    {
        assert!(self.stream_handler.is_none());
        let increase_window = ServerIncreaseInWindow(IncreaseInWindow {
            stream_id: self.stream_id,
            to_write_tx: self.to_write_tx.clone(),
        });
        let (h, r) = f(increase_window, self.in_window_size);
        *self.stream_handler = Some(ServerStreamHandlerHolder(Box::new(h)));
        r
    }
}
<|endoftext|>


<commit_before>extern crate nom_sql;

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn parse_queryset(queries: Vec<String>) -> (i32, i32) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        //println!("Trying to parse '{}': ", &query);
        match nom_sql::parser::parse_query(&query) {
            Ok(_) => {
                //println!("ok");
                parsed_ok.push(query);
            }
            Err(_) => {
                println!("failed: '{}'", &query);
                parsed_err += 1;
            }
        }
    }

    println!("\nParsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    //println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        //println!("{:?}", q);
    }

    (parsed_ok.len() as i32, parsed_err)
}

fn test_queries_from_file(f: &Path, name: &str) -> Result<i32, i32> {
    let mut f = File::open(f).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s
        .lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#") && !l.starts_with("--"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        }).collect();
    println!("\nLoaded {} {} queries", lines.len(), name);

    // Try parsing them all
    let (ok, err) = parse_queryset(lines);

    // For the moment, we're always good
    if err > 0 {
        return Err(err);
    }
    Ok(ok)
}

fn parse_file(path: &str) -> (i32, i32) {
    let mut f = File::open(Path::new(path)).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s
        .lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty()
                && !l.starts_with("#")
                && !l.starts_with("--")
                && !l.starts_with("DROP")
                && !l.starts_with("/*")
        }).collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    parse_queryset(queries)
}

#[test] #[ignore]
fn hotcrp_queries() {
    assert!(test_queries_from_file(Path::new("tests/hotcrp-queries.txt"), "HotCRP").is_ok());
}

#[test]
fn hyrise_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/hyrise-test-queries.txt"), "HyRise").is_ok());
}

#[test]
fn tpcw_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/tpc-w-queries.txt"), "TPC-W").is_ok());
}

#[test]
fn tpcw_test_tables() {
    let res = test_queries_from_file(Path::new("tests/tpc-w-tables.txt"), "TPC-W tables");
    assert!(res.is_ok());
    // There are 10 tables
    assert_eq!(res.unwrap(), 10);
}

#[test]
fn finkelstein82_test_queries() {
    let res = test_queries_from_file(Path::new("tests/finkelstein82.txt"), "Finkelstein 1982");
    assert!(res.is_ok());
    // There are 3 tables and 6 queries
    assert_eq!(res.unwrap(), 9);
}

#[test]
fn hotcrp_schema() {
    let mut f = File::open(Path::new("tests/hotcrp-schema.txt")).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s
        .lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty() && !l.starts_with("#") && !l.starts_with("--") && !l.starts_with("DROP")
        }).collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        // remove inline comments, bah
        let l = match l.find("#") {
            None => l,
            Some(pos) => &l[0..pos - 1],
        };
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    let (ok, fail) = parse_queryset(queries);

    // There are 24 CREATE TABLE queries in the schema
    assert_eq!(ok, 24);
    assert_eq!(fail, 0);
}

#[test]
fn mediawiki_schema() {
    let (ok, fail) = parse_file("tests/mediawiki-schema.txt");

    // There are 17 CREATE TABLE queries in the schema
    assert_eq!(ok, 17);
    assert_eq!(fail, 0);
}

#[test]
fn parse_comments() {
    let (ok, fail) = parse_file("tests/comments.txt");

    // There are 2 CREATE TABLE queries in the schema
    assert_eq!(ok, 2);
    assert_eq!(fail, 0);
}

#[test]
fn parse_autoincrement() {
    let (ok, fail) = parse_file("tests/autoincrement.txt");

    // There is 1 CREATE TABLE queries in the schema
    assert_eq!(ok, 1);
    assert_eq!(fail, 0);
}

#[test]
fn parse_select() {
    let (ok, fail) = parse_file("tests/select.txt");
    assert_eq!(fail, 0);
    assert_eq!(ok, 24);
}
<commit_msg>fixed minor details<commit_after>extern crate nom_sql;

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn parse_queryset(queries: Vec<String>) -> (i32, i32) {
    let mut parsed_ok = Vec::new();
    let mut parsed_err = 0;
    for query in queries.iter() {
        println!("Trying to parse '{}': ", &query);
        match nom_sql::parser::parse_query(&query) {
            Ok(_) => {
                println!("ok");
                parsed_ok.push(query);
            }
            Err(_) => {
                println!("failed");
                parsed_err += 1;
            }
        }
    }

    println!("\nParsing failed: {} queries", parsed_err);
    println!("Parsed successfully: {} queries", parsed_ok.len());
    println!("\nSuccessfully parsed queries:");
    for q in parsed_ok.iter() {
        println!("{:?}", q);
    }

    (parsed_ok.len() as i32, parsed_err)
}

fn test_queries_from_file(f: &Path, name: &str) -> Result<i32, i32> {
    let mut f = File::open(f).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<String> = s
        .lines()
        .filter(|l| !l.is_empty() && !l.starts_with("#") && !l.starts_with("--") && !l.starts_with("/*"))
        .map(|l| {
            if !(l.ends_with("\n") || l.ends_with(";")) {
                String::from(l) + "\n"
            } else {
                String::from(l)
            }
        }).collect();
    println!("\nLoaded {} {} queries", lines.len(), name);

    // Try parsing them all
    let (ok, err) = parse_queryset(lines);

    if err > 0 {
        return Err(err);
    }
    Ok(ok)
}

fn parse_file(path: &str) -> (i32, i32) {
    let mut f = File::open(Path::new(path)).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s
        .lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty()
                && !l.starts_with("#")
                && !l.starts_with("--")
                && !l.starts_with("DROP")
                && !l.starts_with("/*")
        }).collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    parse_queryset(queries)
}

#[test] #[ignore]
fn hotcrp_queries() {
    assert!(test_queries_from_file(Path::new("tests/hotcrp-queries.txt"), "HotCRP").is_ok());
}

#[test]
fn hyrise_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/hyrise-test-queries.txt"), "HyRise").is_ok());
}

#[test]
fn tpcw_test_queries() {
    assert!(test_queries_from_file(Path::new("tests/tpc-w-queries.txt"), "TPC-W").is_ok());
}

#[test]
fn tpcw_test_tables() {
    let res = test_queries_from_file(Path::new("tests/tpc-w-tables.txt"), "TPC-W tables");
    assert!(res.is_ok());
    // There are 10 tables
    assert_eq!(res.unwrap(), 10);
}

#[test]
fn finkelstein82_test_queries() {
    let res = test_queries_from_file(Path::new("tests/finkelstein82.txt"), "Finkelstein 1982");
    assert!(res.is_ok());
    // There are 3 tables and 6 queries
    assert_eq!(res.unwrap(), 9);
}

#[test]
fn hotcrp_schema() {
    let mut f = File::open(Path::new("tests/hotcrp-schema.txt")).unwrap();
    let mut s = String::new();

    // Load queries
    f.read_to_string(&mut s).unwrap();
    let lines: Vec<&str> = s
        .lines()
        .map(str::trim)
        .filter(|l| {
            !l.is_empty() && !l.starts_with("#") && !l.starts_with("--") && !l.starts_with("DROP")
        }).collect();
    let mut q = String::new();
    let mut queries = Vec::new();
    for l in lines {
        // remove inline comments, bah
        let l = match l.find("#") {
            None => l,
            Some(pos) => &l[0..pos - 1],
        };
        if !l.ends_with(";") {
            q.push_str(l);
        } else {
            // end of query
            q.push_str(l);
            queries.push(q.clone());
            q = String::new();
        }
    }
    println!("Loaded {} table definitions", queries.len());

    // Try parsing them all
    let (ok, fail) = parse_queryset(queries);

    // There are 24 CREATE TABLE queries in the schema
    assert_eq!(ok, 24);
    assert_eq!(fail, 0);
}

#[test]
fn mediawiki_schema() {
    let (ok, fail) = parse_file("tests/mediawiki-schema.txt");

    // There are 17 CREATE TABLE queries in the schema
    assert_eq!(ok, 17);
    assert_eq!(fail, 0);
}

#[test]
fn parse_comments() {
    let (ok, fail) = parse_file("tests/comments.txt");

    // There are 2 CREATE TABLE queries in the schema
    assert_eq!(ok, 2);
    assert_eq!(fail, 0);
}

#[test]
fn parse_autoincrement() {
    let (ok, fail) = parse_file("tests/autoincrement.txt");

    // There is 1 CREATE TABLE queries in the schema
    assert_eq!(ok, 1);
    assert_eq!(fail, 0);
}

#[test]
fn parse_select() {
    let (ok, fail) = parse_file("tests/select.txt");
    assert_eq!(fail, 0);
    assert_eq!(ok, 24);
}
<|endoftext|>


<commit_before>//! Tests!
//!
//! Note that since all tests set the global logger, only one can be run at a time in each runtime. In order to
//! successfully run tests, you can use the following:
//!
//! ```sh
//! cargo test -- --exclude test2
//! cargo test test2
//! ```
#[macro_use]
extern crate log;
extern crate fern;
extern crate tempdir;

use std::io::prelude::*;
use std::{fs, io};

#[test]
fn test1_basic_usage() {
    // Create a temporary directory to put a log file into for testing
    let temp_log_dir = tempdir::TempDir::new("fern")
        .expect("Failed to set up temporary directory");
    let log_file = temp_log_dir.path().join("test.log");

    // Create a basic logger configuration
    fern::Dispatch::new()
        .format(|out, msg, record| {
            out.finish(format_args!("[{}] {}", record.level(), msg))
        })
        // Only log messages Info and above
        .level(log::LogLevelFilter::Info)
        // Output to stdout and the log file in the temporary directory we made above to test
        .chain(io::stdout())
        .chain(fern::log_file(log_file).expect("Failed to open log file"))
        .apply()
        .expect("Failed to initialize logger: global logger already set!");

    trace!("SHOULD NOT DISPLAY");
    debug!("SHOULD NOT DISPLAY");
    info!("Test information message");
    warn!("Test warning message");
    error!("Test error message");

    // shutdown the logger, to ensure all File objects are dropped and OS buffers are flushed.
    log::shutdown_logger().expect("Failed to shutdown logger");

    {
        let result = {
            let mut log_read = fs::File::open(&temp_log_dir.path().join("test.log")).unwrap();
            let mut buf = String::new();
            log_read.read_to_string(&mut buf).unwrap();
            buf
        };
        assert!(!result.contains("SHOULD NOT DISPLAY"),
                "expected result not including \"SHOULD_NOT_DISPLAY\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[INFO] Test information message"),
                "expected result including \"[INFO] Test information message\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[WARN] Test warning message"),
                "expected result including \"[WARN] Test warning message\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[ERROR] Test error message"),
                "expected result to not include \"[ERROR] Test error message\", found:\n```\n{}\n```\n",
                result);
    }

    // Just to make sure this goes smoothly - it dose this automatically if we don't .close()
    // manually, but it will ignore any errors when doing it automatically.
    temp_log_dir.close().expect("Failed to clean up temporary directory");
}

#[test]
fn test2_line_seps() {
    // Create a temporary directory to put a log file into for testing
    let temp_log_dir = tempdir::TempDir::new("fern")
        .expect("Failed to set up temporary directory");
    let log_file = temp_log_dir.path().join("test_custom_line_sep.log");

    // Create a basic logger configuration
    fern::Dispatch::new()
        // default format is just the message if not specified
        // default log level is 'trace' if not specified (logs all messages)
        // output to the log file with the "\r\n" line separator.
        .chain(fern::Output::file(fern::log_file(&log_file).expect("Failed to open log file"), "\r\n"))
        .apply()
        .expect("Failed to initialize logger: global logger already set!");

    info!("message1");
    info!("message2");

    // shutdown the logger, to ensure all File objects are dropped and OS buffers are flushed.
    log::shutdown_logger().expect("Failed to shutdown logger");

    {
        let result = {
            let mut log_read = fs::File::open(&temp_log_dir.path().join("test_custom_line_sep.log")).unwrap();
            let mut buf = String::new();
            log_read.read_to_string(&mut buf).unwrap();
            buf
        };
        assert_eq!(&result, "message1\r\nmessage2\r\n");
    }

    // Just to make sure this goes smoothly - it dose this automatically if we don't .close()
    // manually, but it will ignore any errors when doing it automatically.
    temp_log_dir.close().expect("Failed to clean up temporary directory");
}
<commit_msg>Reformat after test changes.<commit_after>//! Tests!
//!
//! Note that since all tests set the global logger, only one can be run at a time in each runtime. In order to
//! successfully run tests, you can use the following:
//!
//! ```sh
//! cargo test -- --exclude test2
//! cargo test test2
//! ```
#[macro_use]
extern crate log;
extern crate fern;
extern crate tempdir;

use std::io::prelude::*;
use std::{fs, io};

#[test]
fn test1_basic_usage() {
    // Create a temporary directory to put a log file into for testing
    let temp_log_dir = tempdir::TempDir::new("fern").expect("Failed to set up temporary directory");
    let log_file = temp_log_dir.path().join("test.log");

    // Create a basic logger configuration
    fern::Dispatch::new()
        .format(|out, msg, record| {
            out.finish(format_args!("[{}] {}", record.level(), msg))
        })
        // Only log messages Info and above
        .level(log::LogLevelFilter::Info)
        // Output to stdout and the log file in the temporary directory we made above to test
        .chain(io::stdout())
        .chain(fern::log_file(log_file).expect("Failed to open log file"))
        .apply()
        .expect("Failed to initialize logger: global logger already set!");

    trace!("SHOULD NOT DISPLAY");
    debug!("SHOULD NOT DISPLAY");
    info!("Test information message");
    warn!("Test warning message");
    error!("Test error message");

    // shutdown the logger, to ensure all File objects are dropped and OS buffers are flushed.
    log::shutdown_logger().expect("Failed to shutdown logger");

    {
        let result = {
            let mut log_read = fs::File::open(&temp_log_dir.path().join("test.log")).unwrap();
            let mut buf = String::new();
            log_read.read_to_string(&mut buf).unwrap();
            buf
        };
        assert!(!result.contains("SHOULD NOT DISPLAY"),
                "expected result not including \"SHOULD_NOT_DISPLAY\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[INFO] Test information message"),
                "expected result including \"[INFO] Test information message\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[WARN] Test warning message"),
                "expected result including \"[WARN] Test warning message\", found:\n```\n{}\n```\n",
                result);
        assert!(result.contains("[ERROR] Test error message"),
                "expected result to not include \"[ERROR] Test error message\", found:\n```\n{}\n```\n",
                result);
    }

    // Just to make sure this goes smoothly - it dose this automatically if we don't .close()
    // manually, but it will ignore any errors when doing it automatically.
    temp_log_dir.close().expect("Failed to clean up temporary directory");
}

#[test]
fn test2_line_seps() {
    // Create a temporary directory to put a log file into for testing
    let temp_log_dir = tempdir::TempDir::new("fern").expect("Failed to set up temporary directory");
    let log_file = temp_log_dir.path().join("test_custom_line_sep.log");

    // Create a basic logger configuration
    fern::Dispatch::new()
        // default format is just the message if not specified
        // default log level is 'trace' if not specified (logs all messages)
        // output to the log file with the "\r\n" line separator.
        .chain(fern::Output::file(fern::log_file(&log_file).expect("Failed to open log file"), "\r\n"))
        .apply()
        .expect("Failed to initialize logger: global logger already set!");

    info!("message1");
    info!("message2");

    // shutdown the logger, to ensure all File objects are dropped and OS buffers are flushed.
    log::shutdown_logger().expect("Failed to shutdown logger");

    {
        let result = {
            let mut log_read = fs::File::open(&temp_log_dir.path().join("test_custom_line_sep.log")).unwrap();
            let mut buf = String::new();
            log_read.read_to_string(&mut buf).unwrap();
            buf
        };
        assert_eq!(&result, "message1\r\nmessage2\r\n");
    }

    // Just to make sure this goes smoothly - it dose this automatically if we don't .close()
    // manually, but it will ignore any errors when doing it automatically.
    temp_log_dir.close().expect("Failed to clean up temporary directory");
}
<|endoftext|>


<commit_before>extern crate tak;

use tak::Game;
use tak::Player;

fn play_no_win(moves: Vec<&str>, game: &mut Game) -> () {
    for str in moves {
        println!("{}", str);
        assert_eq!(game.play_simple(str).unwrap(), None);
    }
}

#[test]
fn basic_placement() {
    let mut game = Game::new(5);
    play_no_win(vec!["Fa2", "d1", "Sa1", "Cd3"], &mut game);
    assert_eq!(game.to_string(),
               "_______________\n\
                |  |  |  |  |  \n\
                |  |  |  |  |  \n\
                |  |  |  |C2|  \n\
                |F2|  |  |  |  \n\
                |S1|  |  |F1|  \n\
                P1: 2/21 Flatstones\n\
                P1: 0/1 Capstones\n\
                P2: 1/21 Flatstones\n\
                P2: 1/1 Capstones\n");
}

#[test]
fn basic_movement() {
    let mut game = Game::new(4);
    play_no_win(vec!["a2", "a1", "a1+", "b1", "2a2>11"], &mut game);
    assert_eq!(game.to_string(),
               "____________\n\
                |  |  |  |  \n\
                |  |  |  |  \n\
                |  |F2|F1|  \n\
                |  |F2|  |  \n\
                P1: 1/15 Flatstones\n\
                P1: 0/0 Capstones\n\
                P2: 2/15 Flatstones\n\
                P2: 0/0 Capstones\n");
}

#[test]
fn break_parser() {
    let mut game = Game::new(4);
    match game.play("0a1", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn must_own_pile_to_move() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-"], &mut game);
    match game.play("1a1>1", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn invalid_movement_onto_standing() {
    let mut game = Game::new(5);
    play_no_win(vec!["a2", "a4", "Sa1"], &mut game);
    match game.play("a2-", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn starting_order() {
    match Game::new(4).play("a2", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn starting_stone() {
    match Game::new(4).play("Sa2", Player::One, Some(Player::Two)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn move_offstage() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2"], &mut game);
    match game.play("a2<", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn under_carry_limit() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1", "a2", "b1<", "a2-", "b1", "5a1>5"],
                &mut game);
}

#[test]
fn carry_limit() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1", "a2", "b1<", "a2-", "b1"], &mut game);
    match game.play("6a1>6", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn movement_amount() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1"], &mut game);
    match game.play("4a1>022", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn invalid_movement_onto_capstone() {
    let mut game = Game::new(5);
    play_no_win(vec!["a2", "c3", "Ca1"], &mut game);
    match game.play("a2-", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn squash() {
    let mut game = Game::new(5);
    play_no_win(vec!["b2", "b1", "Sa1", "Ca2", "b3", "a2-"],
                &mut game);
    assert_eq!(game.to_string(),
               "_________________________\n\
                |    |    |    |    |    \n\
                |    |    |    |    |    \n\
                |    |F1  |    |    |    \n\
                |    |F2  |    |    |    \n\
                |F1C2|F1  |    |    |    \n\
                P1: 3/21 Flatstones\n\
                P1: 0/1 Capstones\n\
                P2: 1/21 Flatstones\n\
                P2: 1/1 Capstones\n");
}

#[test]
fn win_across() {
    let mut game = Game::new(4);
    let m = vec!["b1", "a1", "a2", "b2", "a3", "b3"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("a4", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn almost() {
    play_no_win(vec!["a2", "a1", "b1", "b2", "c1"],
                &mut Game::new(4));
}

#[test]
fn almost2() {
    play_no_win(vec!["a2", "b1", "c1", "b2", "d1"],
                &mut Game::new(4));
}

#[test]
fn win_up() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("d1", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn cant_win_with_standing() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("Sd1", Player::One, Some(Player::One)).unwrap(), None);
}

#[test]
fn all_pieces() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "a3", "a4", "b2", "b1", "b4", "b3", "c1", "c2",
                 "c3", "c4", "d2", "d1", "d4", "d1<", "d1", "b1<", "b1", "a2>",
                 "a2", "c2>", "c2", "b3<", "b3", "a4>", "a4", "c4<"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("c4", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn all_pieces_with_cap() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "Ca2", "e1+", "a3", "e2-", "a4", "e1+", "b1", "e2-",
                 "b2", "e1+", "b3", "e2-", "b4", "e1+", "c1", "e2-", "c2", "e1+",
                 "c3", "e2-", "c4", "e1+", "d1", "e2-", "d2", "e1+", "d3", "e2-",
                 "d4", "e1+", "d4<", "e2<", "d3<", "2d2-2", "d4", "3d1<3", "d3",
                 "c1+", "d2", "2c2<2", "d1", "e1"];
    play_no_win(m, &mut game);
    println!("{}", game.as_ptn());
    assert_eq!(game.play("e5", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn full_board() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "a3", "a4", "b2", "b1", "b4", "b3", "c1", "c2",
                 "c3", "c4", "d2", "d1", "d4"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("d3", Player::Two, Some(Player::Two)).unwrap(), Some(Player::Two));
}

#[test]
fn cannot_play_too_many_capstones() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "Cc3", "c2"];
    play_no_win(m, &mut game);
    match game.play("Cc4", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn cannot_play_too_many_flats() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "a2", "e1+", "a3", "e2-", "a4", "e1+", "b1", "e2-",
                 "b2", "e1+", "b3", "e2-", "b4", "e1+", "c1", "e2-", "c2", "e1+",
                 "c3", "e2-", "c4", "e1+", "d1", "e2-", "d2", "e1+", "d3", "e2-",
                 "d4", "e1+", "d4<", "e2<", "d3<", "2d2-2", "d4", "3d1<3", "d3",
                 "c1+", "d2", "2c2<2", "d1", "e1", "c2", "e3"];
    play_no_win(m, &mut game);
    match game.play("e5", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn convoluted_road_win() {
    let mut game = Game::new(6);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2", "d1", "e1", "d2", "e2",
                 "d3", "e3", "c3", "e4", "b3", "d4", "b4", "c4", "b5", "a3",
                 "c5", "a4", "d5", "a5", "e5", "a6"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("f5", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn example1() {
    let mut game = Game::new(5);
    let m = vec!["a1", "e1", "c3", "a3", "e3", "a4", "a2", "a5", "b4", "d3",
                 "e2", "e4", "d2", "b2", "b4<", "a3+", "a3", "3a4-12", "a4", "b3",
                 "b4", "b3+", "a4+", "a4", "b3", "2b4-2", "d4", "b5", "2a5-11",
                 "3b3<3", "a5"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("a4+", Player::Two, None).unwrap(), Some(Player::Two));
}
<commit_msg>Fix failing test<commit_after>extern crate tak;

use tak::Game;
use tak::Player;

fn play_no_win(moves: Vec<&str>, game: &mut Game) -> () {
    for str in moves {
        println!("{}", str);
        assert_eq!(game.play_simple(str).unwrap(), None);
    }
}

#[test]
fn basic_placement() {
    let mut game = Game::new(5);
    play_no_win(vec!["Fa2", "d1", "Sa1", "Cd3"], &mut game);
    assert_eq!(game.to_string(),
               "_______________\n\
                |  |  |  |  |  \n\
                |  |  |  |  |  \n\
                |  |  |  |C2|  \n\
                |F2|  |  |  |  \n\
                |S1|  |  |F1|  \n\
                P1: 2/21 Flatstones\n\
                P1: 0/1 Capstones\n\
                P2: 1/21 Flatstones\n\
                P2: 1/1 Capstones\n");
}

#[test]
fn basic_movement() {
    let mut game = Game::new(4);
    play_no_win(vec!["a2", "a1", "a1+", "b1", "2a2>11"], &mut game);
    assert_eq!(game.to_string(),
               "____________\n\
                |  |  |  |  \n\
                |  |  |  |  \n\
                |  |F2|F1|  \n\
                |  |F2|  |  \n\
                P1: 1/15 Flatstones\n\
                P1: 0/0 Capstones\n\
                P2: 2/15 Flatstones\n\
                P2: 0/0 Capstones\n");
}

#[test]
fn break_parser() {
    let mut game = Game::new(4);
    match game.play("0a1", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn must_own_pile_to_move() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-"], &mut game);
    match game.play("1a1>1", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn invalid_movement_onto_standing() {
    let mut game = Game::new(5);
    play_no_win(vec!["a2", "a4", "Sa1"], &mut game);
    match game.play("a2-", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn starting_order() {
    match Game::new(4).play("a2", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn starting_stone() {
    match Game::new(4).play("Sa2", Player::One, Some(Player::Two)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn move_offstage() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2"], &mut game);
    match game.play("a2<", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn under_carry_limit() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1", "a2", "b1<", "a2-", "b1", "5a1>5"],
                &mut game);
}

#[test]
fn carry_limit() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1", "a2", "b1<", "a2-", "b1"], &mut game);
    match game.play("6a1>6", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn movement_amount() {
    let mut game = Game::new(5);
    play_no_win(vec!["a1", "a2", "a2-", "b1", "a2", "b1<", "a2-",
                     "b1"], &mut game);
    match game.play("4a1>022", Player::One, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn invalid_movement_onto_capstone() {
    let mut game = Game::new(5);
    play_no_win(vec!["a2", "c3", "Ca1"], &mut game);
    match game.play("a2-", Player::Two, None) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn squash() {
    let mut game = Game::new(5);
    play_no_win(vec!["b2", "b1", "Sa1", "Ca2", "b3", "a2-"],
                &mut game);
    assert_eq!(game.to_string(),
               "_________________________\n\
                |    |    |    |    |    \n\
                |    |    |    |    |    \n\
                |    |F1  |    |    |    \n\
                |    |F2  |    |    |    \n\
                |F1C2|F1  |    |    |    \n\
                P1: 3/21 Flatstones\n\
                P1: 0/1 Capstones\n\
                P2: 1/21 Flatstones\n\
                P2: 1/1 Capstones\n");
}

#[test]
fn win_across() {
    let mut game = Game::new(4);
    let m = vec!["b1", "a1", "a2", "b2", "a3", "b3"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("a4", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn almost() {
    play_no_win(vec!["a2", "a1", "b1", "b2", "c1"],
                &mut Game::new(4));
}

#[test]
fn almost2() {
    play_no_win(vec!["a2", "b1", "c1", "b2", "d1"],
                &mut Game::new(4));
}

#[test]
fn win_up() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("d1", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn cant_win_with_standing() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("Sd1", Player::One, Some(Player::One)).unwrap(), None);
}

#[test]
fn all_pieces() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "a3", "a4", "b2", "b1", "b4", "b3", "c1", "c2",
                 "c3", "c4", "d2", "d1", "d4", "d1<", "d1", "b1<", "b1", "a2>",
                 "a2", "c2>", "c2", "b3<", "b3", "a4>", "a4", "c4<"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("c4", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn all_pieces_with_cap() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "Ca2", "e1+", "a3", "e2-", "a4", "e1+", "b1", "e2-",
                 "b2", "e1+", "b3", "e2-", "b4", "e1+", "c1", "e2-", "c2", "e1+",
                 "c3", "e2-", "c4", "e1+", "d1", "e2-", "d2", "e1+", "d3", "e2-",
                 "d4", "e1+", "d4<", "e2<", "d3<", "2d2-2", "d4", "3d1<3", "d3",
                 "c1+", "d2", "2c2<2", "d1", "e1", "c2", "e2"];
    play_no_win(m, &mut game);
    println!("{}", game.as_ptn());
    assert_eq!(game.play("e5", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn full_board() {
    let mut game = Game::new(4);
    let m = vec!["a2", "a1", "a3", "a4", "b2", "b1", "b4", "b3", "c1", "c2",
                 "c3", "c4", "d2", "d1", "d4"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("d3", Player::Two, Some(Player::Two)).unwrap(), Some(Player::Two));
}

#[test]
fn cannot_play_too_many_capstones() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "Cc3", "c2"];
    play_no_win(m, &mut game);
    match game.play("Cc4", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn cannot_play_too_many_flats() {
    let mut game = Game::new(5);
    let m = vec!["e1", "a1", "a2", "e1+", "a3", "e2-", "a4", "e1+", "b1", "e2-",
                 "b2", "e1+", "b3", "e2-", "b4", "e1+", "c1", "e2-", "c2", "e1+",
                 "c3", "e2-", "c4", "e1+", "d1", "e2-", "d2", "e1+", "d3", "e2-",
                 "d4", "e1+", "d4<", "e2<", "d3<", "2d2-2", "d4", "3d1<3", "d3",
                 "c1+", "d2", "2c2<2", "d1", "e1", "c2", "e3"];
    play_no_win(m, &mut game);
    match game.play("e5", Player::One, Some(Player::One)) {
        Ok(_) => panic!(""),
        Err(_) => return,
    }
}

#[test]
fn convoluted_road_win() {
    let mut game = Game::new(6);
    let m = vec!["a2", "a1", "b1", "b2", "c1", "c2", "d1", "e1", "d2", "e2",
                 "d3", "e3", "c3", "e4", "b3", "d4", "b4", "c4", "b5", "a3",
                 "c5", "a4", "d5", "a5", "e5", "a6"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("f5", Player::One, Some(Player::One)).unwrap(), Some(Player::One));
}

#[test]
fn example1() {
    let mut game = Game::new(5);
    let m = vec!["a1", "e1", "c3", "a3", "e3", "a4", "a2", "a5", "b4", "d3",
                 "e2", "e4", "d2", "b2", "b4<", "a3+", "a3", "3a4-12", "a4", "b3",
                 "b4", "b3+", "a4+", "a4", "b3", "2b4-2", "d4", "b5", "2a5-11",
                 "3b3<3", "a5"];
    play_no_win(m, &mut game);
    assert_eq!(game.play("a4+", Player::Two, None).unwrap(), Some(Player::Two));
}
<|endoftext|>


<commit_before>
use npffi;
use pyffi;
use cpython::*;
use npffi::types::npy_intp;
use super::{NPY_TYPES, NPY_ORDER};

pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npffi::PyArrayObject {
        self.0.as_ptr() as *mut npffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npffi::PyArrayObject {
        self.0.steal_ptr() as *mut npffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    pub fn zeros(py: Python, dims: &[usize], typenum: NPY_TYPES, order: NPY_ORDER) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = npffi::PyArray_DescrFromType(typenum as i32);
            let ptr = npffi::PyArray_Zeros(dims.len() as i32,
                                           dims.as_ptr() as *mut npy_intp,
                                           descr,
                                           order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<commit_msg>Add accessors: ndim/dims/strides<commit_after>
use npffi;
use pyffi;
use cpython::*;
use npffi::types::npy_intp;
use super::{NPY_TYPES, NPY_ORDER};

pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npffi::PyArrayObject {
        self.0.as_ptr() as *mut npffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npffi::PyArrayObject {
        self.0.steal_ptr() as *mut npffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    pub fn ndim(&self) -> usize {
        let ptr = self.as_ptr();
        unsafe { (*ptr).nd as usize }
    }

    pub fn dims(&self) -> Vec<usize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).dimensions;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as usize).collect()
    }

    pub fn strides(&self) -> Vec<isize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as isize).collect()
    }

    pub fn zeros(py: Python, dims: &[usize], typenum: NPY_TYPES, order: NPY_ORDER) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = npffi::PyArray_DescrFromType(typenum as i32);
            let ptr = npffi::PyArray_Zeros(dims.len() as i32,
                                           dims.as_ptr() as *mut npy_intp,
                                           descr,
                                           order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        unsafe {
            if npffi::PyArray_Check(obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<|endoftext|>


<commit_before>// while a WIP
#![allow(unused_variables)]
use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};
use serde::{Serialize, Deserialize, Serializer, Deserializer};

use storage::*;
use ::*;
pub use tensor::tensor_ops::*;
use rand;
use {Ixs, RcMut};

pub enum TensorType {
    Float,
    Double,
    Byte,
    Char,
    Short,
    Int,
    Long,
}

#[derive(Hash, Serialize, Deserialize)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}
pub enum NumKind {
    Float(f32),
    Double(f64),
    Long(i64),
}

impl NumKind {
    pub fn intof32(&self) -> f32 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Float(v) => v,
            _ => unimplemented!(),
        }
    }
    pub fn intoi64(&self) -> i64 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Long(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl<T: Copy> From<T> for NumKind {
    #[allow(unused_variables)]
    default fn from(input: T) -> Self {
        unreachable!()
    }
}
impl From<f32> for NumKind {
    fn from(input: f32) -> Self {
        NumKind::Float(input)
    }
}
impl From<f64> for NumKind {
    fn from(input: f64) -> Self {
        NumKind::Double(input)
    }
}
impl From<i64> for NumKind {
    fn from(input: i64) -> Self {
        NumKind::Long(input)
    }
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type OptTensorKindList = Vec<Option<TensorKind>>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = usize;

impl TensorKind {
    pub fn backend(&self) -> Box<nn::BackendIntf> {
        unimplemented!()
    }
    pub fn inner(&self) -> *mut ::std::os::raw::c_void {
        unimplemented!()
    }
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl Index<usize> for TensorKind {
    type Output = NumKind;
    fn index(&self, idx: usize) -> &Self::Output {
        unimplemented!()
    }
}
impl PartialEq for TensorKind {
    fn eq(&self, other: &Self) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id() == t2.id(),
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id() == t2.id(),
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> Self {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> Self {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

pub struct Tensor<T> {
    pub value: RcMut<TensorImpl<T, Output = T>>,
}

impl<T> Serialize for Tensor<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        unimplemented!()
    }
}
impl<'de, T> Deserialize<'de> for Tensor<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        unimplemented!()
    }
}

impl<T: Copy> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id().hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
}
pub trait NewSelf<D, T> {
    fn new(&self, args: D) -> T;
}

impl<T> NewSelf<usize, Tensor<T>> for Tensor<T> {
    fn new(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> NewSelf<(), Tensor<T>> for Tensor<T> {
    fn new(&self, args: ()) -> Self {
        unimplemented!()
    }
}
impl<T> NewSelf<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}
impl NewSelf<usize, TensorKind> for TensorKind {
    fn new(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl NewSelf<(), TensorKind> for TensorKind {
    fn new(&self, args: ()) -> Self {
        unimplemented!()
    }
}
impl NewSelf<Vec<usize>, TensorKind> for TensorKind {
    fn new(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}
impl NewSelf<[usize; 2], TensorKind> for TensorKind {
    fn new(&self, args: [usize; 2]) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
    pub fn cast<D>&self) -> Tensor<D> {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor { value: self.value.clone() }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

type RefTI<T> = RcMut<TensorImpl<T, Output = T>>;
pub type TIArg<T> = TensorImpl<T, Output = T>;
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
    fn new(&self) -> RefTI<T>;
    fn add(&self, value: T, output: &TIArg<T>);
    fn addt(&self, value: T, rhs: &TIArg<T>, output: &TIArg<T>);
    fn inner(&self) -> *mut ::std::os::raw::c_void;
}

impl TensorImpl<f32> for FloatTensor {
    fn new(&self) -> RefTI<f32> {
        // XXX place holder implementation
        RcMutNew(FloatTensor::new())
    }
    fn add(&self, value: f32, output: &TIArg<f32>) {
        let out = typecast!(output.inner(), THFloatTensor);
        unsafe {
            THFloatTensor_add(out, self.t, value);
        };
    }
    fn inner(&self) -> *mut ::std::os::raw::c_void {
        self.t as *mut ::std::os::raw::c_void
    }
    fn addt(&self, value: f32, rhs: &TIArg<f32>, output: &TIArg<f32>) {
        let rhsp = typecast!(rhs.inner(), THFloatTensor);
    }
}

impl Index<isize> for FloatTensor {
    type Output = f32;
    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

impl Serialize for FloatTensor {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        unimplemented!()
    }
}
impl<'de> Deserialize<'de> for FloatTensor {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        unimplemented!()
    }
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

impl Default for FloatTensor {
    fn default() -> Self {
        FloatTensor::new()
    }
}

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

pub fn make_vec(val: usize, count: usize) -> Vec<isize> {
    let mut vec = Vec::new();
    for _ in 0..count {
        vec.push(val as isize)
    }
    vec
}
<commit_msg>fix compile<commit_after>// while a WIP
#![allow(unused_variables)]
use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};
use serde::{Serialize, Deserialize, Serializer, Deserializer};

use storage::*;
use ::*;
pub use tensor::tensor_ops::*;
use rand;
use {Ixs, RcMut};

pub enum TensorType {
    Float,
    Double,
    Byte,
    Char,
    Short,
    Int,
    Long,
}

#[derive(Hash, Serialize, Deserialize)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}
pub enum NumKind {
    Float(f32),
    Double(f64),
    Long(i64),
}

impl NumKind {
    pub fn intof32(&self) -> f32 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Float(v) => v,
            _ => unimplemented!(),
        }
    }
    pub fn intoi64(&self) -> i64 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Long(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl<T: Copy> From<T> for NumKind {
    #[allow(unused_variables)]
    default fn from(input: T) -> Self {
        unreachable!()
    }
}
impl From<f32> for NumKind {
    fn from(input: f32) -> Self {
        NumKind::Float(input)
    }
}
impl From<f64> for NumKind {
    fn from(input: f64) -> Self {
        NumKind::Double(input)
    }
}
impl From<i64> for NumKind {
    fn from(input: i64) -> Self {
        NumKind::Long(input)
    }
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type OptTensorKindList = Vec<Option<TensorKind>>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = usize;

impl TensorKind {
    pub fn backend(&self) -> Box<nn::BackendIntf> {
        unimplemented!()
    }
    pub fn inner(&self) -> *mut ::std::os::raw::c_void {
        unimplemented!()
    }
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl Index<usize> for TensorKind {
    type Output = NumKind;
    fn index(&self, idx: usize) -> &Self::Output {
        unimplemented!()
    }
}
impl PartialEq for TensorKind {
    fn eq(&self, other: &Self) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id() == t2.id(),
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id() == t2.id(),
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> Self {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> Self {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

pub struct Tensor<T> {
    pub value: RcMut<TensorImpl<T, Output = T>>,
}

impl<T> Serialize for Tensor<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        unimplemented!()
    }
}
impl<'de, T> Deserialize<'de> for Tensor<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        unimplemented!()
    }
}

impl<T: Copy> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id().hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
}
pub trait NewSelf<D, T> {
    fn new(&self, args: D) -> T;
}

impl<T> NewSelf<usize, Tensor<T>> for Tensor<T> {
    fn new(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> NewSelf<(), Tensor<T>> for Tensor<T> {
    fn new(&self, args: ()) -> Self {
        unimplemented!()
    }
}
impl<T> NewSelf<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}
impl NewSelf<usize, TensorKind> for TensorKind {
    fn new(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl NewSelf<(), TensorKind> for TensorKind {
    fn new(&self, args: ()) -> Self {
        unimplemented!()
    }
}
impl NewSelf<Vec<usize>, TensorKind> for TensorKind {
    fn new(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}
impl NewSelf<[usize; 2], TensorKind> for TensorKind {
    fn new(&self, args: [usize; 2]) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
    pub fn cast<D>(&self) -> Tensor<D> {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor { value: self.value.clone() }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

type RefTI<T> = RcMut<TensorImpl<T, Output = T>>;
pub type TIArg<T> = TensorImpl<T, Output = T>;
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
    fn new(&self) -> RefTI<T>;
    fn add(&self, value: T, output: &TIArg<T>);
    fn addt(&self, value: T, rhs: &TIArg<T>, output: &TIArg<T>);
    fn inner(&self) -> *mut ::std::os::raw::c_void;
}

impl TensorImpl<f32> for FloatTensor {
    fn new(&self) -> RefTI<f32> {
        // XXX place holder implementation
        RcMutNew(FloatTensor::new())
    }
    fn add(&self, value: f32, output: &TIArg<f32>) {
        let out = typecast!(output.inner(), THFloatTensor);
        unsafe {
            THFloatTensor_add(out, self.t, value);
        };
    }
    fn inner(&self) -> *mut ::std::os::raw::c_void {
        self.t as *mut ::std::os::raw::c_void
    }
    fn addt(&self, value: f32, rhs: &TIArg<f32>, output: &TIArg<f32>) {
        let rhsp = typecast!(rhs.inner(), THFloatTensor);
    }
}

impl Index<isize> for FloatTensor {
    type Output = f32;
    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

impl Serialize for FloatTensor {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        unimplemented!()
    }
}
impl<'de> Deserialize<'de> for FloatTensor {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        unimplemented!()
    }
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

impl Default for FloatTensor {
    fn default() -> Self {
        FloatTensor::new()
    }
}

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

pub fn make_vec(val: usize, count: usize) -> Vec<isize> {
    let mut vec = Vec::new();
    for _ in 0..count {
        vec.push(val as isize)
    }
    vec
}
<|endoftext|>