<commit_before>#[macro_use]
extern crate serde_derive;
extern crate blockchain_explorer;
extern crate sandbox;
extern crate exonum;
extern crate configuration_service;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate log;

#[cfg(test)]
mod tests {

    use std::collections::BTreeMap;
    use exonum::storage::Map;
    use exonum::messages::Message;
    use exonum::blockchain::config::StoredConfiguration;
    use exonum::blockchain::Service;
    use sandbox::sandbox_with_services;
    use sandbox::sandbox::Sandbox;
    use sandbox::timestamping::TimestampingService;
    use sandbox::sandbox_tests_helper::{SandboxState, add_one_height_with_transactions};
    use configuration_service::{TxConfigPropose, TxConfigVote, ConfigurationService,
                                ConfigurationSchema};
    use serde_json::{to_vec, Value};
    use serde_json::value::ToJson;
    use blockchain_explorer;

    pub fn configuration_sandbox() -> Sandbox {
        let sandbox = sandbox_with_services(vec![Box::new(TimestampingService::new()),
                                                 Box::new(ConfigurationService::new())]);
        sandbox
    }

    #[derive(Serialize)]
    struct CfgStub {
        cfg_string: String,
    }

    #[test]
    fn change_service_config() {
        blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();
        let initial_cfg = sandbox.cfg();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(5, 1);

        let services = gen_timestamping_cfg("First cfg");

        let new_cfg = StoredConfiguration {
            actual_from: 7,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        // let ser_conf = to_vec(new_cfg).unwrap();
        let propose_tx = TxConfigPropose::new(&sandbox.p(1),
                                              5,
                                              &to_vec(&new_cfg).unwrap(),
                                              6,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx.raw().clone()]);
        sandbox.assert_state(6, 1);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        let propose_hash = propose_tx.hash();

        assert_eq!(propose_tx, proposes.get(&propose_hash).unwrap().unwrap());
        let vote1 = TxConfigVote::new(&sandbox.p(0), 5, &propose_hash, 1700, false, sandbox.s(0));
        let vote2 = TxConfigVote::new(&sandbox.p(1), 5, &propose_hash, 1700, false, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[vote1.raw().clone(), vote2.raw().clone()]);
        sandbox.assert_state(7, 1);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes();
        assert_eq!(vote1, votes.get(&sandbox.p(0)).unwrap().unwrap());
        assert_eq!(vote2, votes.get(&sandbox.p(1)).unwrap().unwrap());
        assert_eq!(None, votes.get(&sandbox.p(2)).unwrap());
        assert_eq!(initial_cfg, sandbox.cfg());

        let vote3 = TxConfigVote::new(&sandbox.p(2), 5, &propose_hash, 1700, false, sandbox.s(2));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[vote3.raw().clone()]);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes();
        sandbox.assert_state(8, 1);
        assert_eq!(vote3, votes.get(&sandbox.p(2)).unwrap().unwrap());
        assert_eq!(new_cfg, sandbox.cfg());
    }

    fn gen_timestamping_cfg(cfg_message: &str) -> BTreeMap<u16, Value> {
        let mut services: BTreeMap<u16, Value> = BTreeMap::new();
        let tmstmp_id = TimestampingService::new().service_id();
        let service_cfg = CfgStub { cfg_string: cfg_message.to_string() };
        services.insert(tmstmp_id, service_cfg.to_json());
        services
    }

    /// regression: votes' were summed for all proposes simultaneously, and not for the same propose
    #[test]
    fn regression_majority_votes_for_different_proposes() {

        blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 4;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg1).unwrap(),
                                               actual_from,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg2).unwrap(),
                                               actual_from,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let pr_hash1 = propose_tx1.hash();
        let pr_hash2 = propose_tx2.hash();
        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1700, false, sandbox.s(0));
        let prop1_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash1, 1700, false, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(), prop1_validator1.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop2_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash2, 1700, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(initial_cfg, sandbox.cfg());
    }

    #[test]
    fn regression_new_vote_for_older_config_applies_old_config() {

        blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 4;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg1).unwrap(),
                                               actual_from,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg2).unwrap(),
                                               actual_from,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let pr_hash1 = propose_tx1.hash();
        let pr_hash2 = propose_tx2.hash();
        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1700, false, sandbox.s(0));
        let prop1_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash1, 1700, false, sandbox.s(1));
        let prop1_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash1, 1700, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(), prop1_validator1.raw().clone(), prop1_validator2.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(new_cfg1, sandbox.cfg());

        let prop2_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash2, 1701, false, sandbox.s(0));
        let prop2_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash2, 1701, false, sandbox.s(1));
        let prop2_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash2, 1701, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator0.raw().clone(), prop2_validator1.raw().clone(), prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(new_cfg2, sandbox.cfg());

        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1702, false, sandbox.s(0));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg2, sandbox.cfg());
    }
}
<commit_msg>Added swap(i,j) method to List interface<commit_after>#[macro_use]
extern crate serde_derive;
extern crate blockchain_explorer;
extern crate sandbox;
extern crate exonum;
extern crate configuration_service;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate log;

#[cfg(test)]
mod tests {

    use std::collections::BTreeMap;
    use exonum::storage::Map;
    use exonum::messages::Message;
    use exonum::blockchain::config::StoredConfiguration;
    use exonum::blockchain::Service;
    use sandbox::sandbox_with_services;
    use sandbox::sandbox::Sandbox;
    use sandbox::timestamping::TimestampingService;
    use sandbox::sandbox_tests_helper::{SandboxState, add_one_height_with_transactions};
    use configuration_service::{TxConfigPropose, TxConfigVote, ConfigurationService,
                                ConfigurationSchema};
    use serde_json::{to_vec, Value};
    use serde_json::value::ToJson;
    use blockchain_explorer;

    pub fn configuration_sandbox() -> Sandbox {
        let sandbox = sandbox_with_services(vec![Box::new(TimestampingService::new()),
                                                 Box::new(ConfigurationService::new())]);
        sandbox
    }

    #[derive(Serialize)]
    struct CfgStub {
        cfg_string: String,
    }

    #[test]
    fn test_change_service_config() {
        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();
        let initial_cfg = sandbox.cfg();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(5, 1);

        let services = gen_timestamping_cfg("First cfg");

        let new_cfg = StoredConfiguration {
            actual_from: 7,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        // let ser_conf = to_vec(new_cfg).unwrap();
        let propose_tx = TxConfigPropose::new(&sandbox.p(1),
                                              5,
                                              &to_vec(&new_cfg).unwrap(),
                                              6,
                                              sandbox.s(1));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[propose_tx.raw().clone()]);
        sandbox.assert_state(6, 1);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let proposes = schema.config_proposes();
        let propose_hash = propose_tx.hash();

        assert_eq!(propose_tx, proposes.get(&propose_hash).unwrap().unwrap());
        let vote1 = TxConfigVote::new(&sandbox.p(0), 5, &propose_hash, 1700, false, sandbox.s(0));
        let vote2 = TxConfigVote::new(&sandbox.p(1), 5, &propose_hash, 1700, false, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[vote1.raw().clone(), vote2.raw().clone()]);
        sandbox.assert_state(7, 1);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes();
        assert_eq!(vote1, votes.get(&sandbox.p(0)).unwrap().unwrap());
        assert_eq!(vote2, votes.get(&sandbox.p(1)).unwrap().unwrap());
        assert_eq!(None, votes.get(&sandbox.p(2)).unwrap());
        assert_eq!(initial_cfg, sandbox.cfg());

        let vote3 = TxConfigVote::new(&sandbox.p(2), 5, &propose_hash, 1700, false, sandbox.s(2));
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[vote3.raw().clone()]);
        let view = sandbox.blockchain_copy().view();
        let schema = ConfigurationSchema::new(&view);
        let votes = schema.config_votes();
        sandbox.assert_state(8, 1);
        assert_eq!(vote3, votes.get(&sandbox.p(2)).unwrap().unwrap());
        assert_eq!(new_cfg, sandbox.cfg());
    }

    fn gen_timestamping_cfg(cfg_message: &str) -> BTreeMap<u16, Value> {
        let mut services: BTreeMap<u16, Value> = BTreeMap::new();
        let tmstmp_id = TimestampingService::new().service_id();
        let service_cfg = CfgStub { cfg_string: cfg_message.to_string() };
        services.insert(tmstmp_id, service_cfg.to_json());
        services
    }

    /// regression: votes' were summed for all proposes simultaneously, and not for the same propose
    #[test]
    fn test_regression_majority_votes_for_different_proposes() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        let initial_cfg = sandbox.cfg();
        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 4;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };

        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg1).unwrap(),
                                               actual_from,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg2).unwrap(),
                                               actual_from,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let pr_hash1 = propose_tx1.hash();
        let pr_hash2 = propose_tx2.hash();
        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1700, false, sandbox.s(0));
        let prop1_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash1, 1700, false, sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(), prop1_validator1.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(initial_cfg, sandbox.cfg());

        let prop2_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash2, 1700, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(initial_cfg, sandbox.cfg());
    }

    #[test]
    fn test_regression_new_vote_for_older_config_applies_old_config() {

        let _ = blockchain_explorer::helpers::init_logger();
        let sandbox = configuration_sandbox();
        let sandbox_state = SandboxState::new();

        add_one_height_with_transactions(&sandbox, &sandbox_state, &[]);
        sandbox.assert_state(2, 1);

        let actual_from = 4;

        let services = gen_timestamping_cfg("First cfg");
        let new_cfg1 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let services = gen_timestamping_cfg("Second cfg");
        let new_cfg2 = StoredConfiguration {
            actual_from: actual_from,
            validators: sandbox.validators(),
            consensus: sandbox.cfg().consensus,
            services: services,
        };
        let propose_tx1 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg1).unwrap(),
                                               actual_from,
                                               sandbox.s(1));
        let propose_tx2 = TxConfigPropose::new(&sandbox.p(1),
                                               5,
                                               &to_vec(&new_cfg2).unwrap(),
                                               actual_from,
                                               sandbox.s(1));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[propose_tx1.raw().clone(), propose_tx2.raw().clone()]);
        sandbox.assert_state(3, 1);

        let pr_hash1 = propose_tx1.hash();
        let pr_hash2 = propose_tx2.hash();
        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1700, false, sandbox.s(0));
        let prop1_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash1, 1700, false, sandbox.s(1));
        let prop1_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash1, 1700, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone(), prop1_validator1.raw().clone(), prop1_validator2.raw().clone()]);
        sandbox.assert_state(4, 1);
        assert_eq!(new_cfg1, sandbox.cfg());

        let prop2_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash2, 1701, false, sandbox.s(0));
        let prop2_validator1 = TxConfigVote::new(&sandbox.p(1), 5, &pr_hash2, 1701, false, sandbox.s(1));
        let prop2_validator2 = TxConfigVote::new(&sandbox.p(2), 5, &pr_hash2, 1701, false, sandbox.s(2));

        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop2_validator0.raw().clone(), prop2_validator1.raw().clone(), prop2_validator2.raw().clone()]);
        sandbox.assert_state(5, 1);
        assert_eq!(new_cfg2, sandbox.cfg());

        let prop1_validator0 = TxConfigVote::new(&sandbox.p(0), 5, &pr_hash1, 1702, false, sandbox.s(0));
        add_one_height_with_transactions(&sandbox,
                                         &sandbox_state,
                                         &[prop1_validator0.raw().clone()]);
        sandbox.assert_state(6, 1);
        assert_eq!(new_cfg2, sandbox.cfg());
    }
}
<|endoftext|>


<commit_before>use types::*;

use cookie_factory::*;

/* TODO: use AMQP types when something like call!() is available */

pub fn gen_boolean<'a>(x: (&'a mut [u8], usize), b: &Boolean) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, if *b { 1 } else { 0 })
}

/*
pub fn gen_short_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i8!(x, *i)
}
*/

pub fn gen_short_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, *u)
}

/*
pub fn gen_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i16!(x, *i)
}
*/

pub fn gen_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u16!(x, *u)
}

/*
pub fn gen_long_int<'a>(x: (&'a mut [u8], usize), i: &LongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i32!(x, *i)
}
*/

pub fn gen_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u32!(x, *u)
}

/*
pub fn gen_long_long_int<'a>(x: (&'a mut [u8], usize), i: &LongLongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i64!(x, *i)
}
*/

pub fn gen_long_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongLongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u64!(x, *u)
}

/* TODO: Float, Double */

pub fn gen_decimal_value<'a>(x: (&'a mut [u8], usize), d: &DecimalValue) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u8!(d.scale) >> gen_be_u32!(d.value))
}

pub fn gen_short_string<'a>(x: (&'a mut [u8], usize), s: &ShortString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u8!(s.len() as u8) >> gen_slice!(s.as_bytes()))
}

pub fn gen_long_string<'a>(x: (&'a mut [u8], usize), s: &LongString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u32!(s.len() as u32) >> gen_slice!(s.as_bytes()))
}

/* TODO: FieldArray */

pub fn gen_timestamp<'a>(x: (&'a mut [u8], usize), t: &Timestamp) -> Result<(&'a mut [u8], usize), GenError> {
    gen_long_long_uint(x, t)
}

/* TODO: FieldTable */
<commit_msg>types: generate values and arrays<commit_after>use types::*;

use cookie_factory::*;

/* TODO: use AMQP types and call gen_type when something like call!() is available */

pub fn gen_value<'a>(x: (&'a mut [u8], usize), v: &AMQPValue) -> Result<(&'a mut [u8], usize), GenError> {
    match *v {
        AMQPValue::Boolean(ref b)        => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_boolean(b)),
//        AMQPValue::ShortShortInt(ref i)  => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_short_short_int(i)),
        AMQPValue::ShortShortUInt(ref u) => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_short_short_uint(u)),
//        AMQPValue::ShortInt(ref i)       => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_short_int(i)),
        AMQPValue::ShortUInt(ref u)      => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_short_uint(u)),
//        AMQPValue::LongInt(ref i)        => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_long_int(i)),
        AMQPValue::LongUInt(ref u)       => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_long_uint(u)),
//        AMQPValue::LongLongInt(ref i)    => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_long_long_int(i)),
        AMQPValue::LongLongUInt(ref u)   => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_long_long_uint(u)),
//        AMQPValue::Float(ref f)          => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_float(f)),
//        AMQPValue::Double(ref d)         => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_double(d)),
        AMQPValue::DecimalValue(ref d)   => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_decimal_value(d)),
        AMQPValue::ShortString(ref s)    => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_short_string(s)),
        AMQPValue::LongString(ref s)     => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_long_string(s)),
        AMQPValue::FieldArray(ref a)     => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_field_array(a)),
        AMQPValue::Timestamp(ref t)      => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_timestamp(t)),
//        AMQPValue::FieldTable(ref t)     => do_gen!(x, gen_be_u8!(v.get_type().get_id() as u8) >> gen_field_table(t)),
        AMQPValue::Void                  => gen_be_u8!(x, v.get_type().get_id() as u8),
        _                                => Err(GenError::CustomError(42))
    }
}

pub fn gen_type<'a>(x: (&'a mut [u8], usize), t: &AMQPType) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, t.get_id() as u8)
}

pub fn gen_boolean<'a>(x: (&'a mut [u8], usize), b: &Boolean) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, if *b { 1 } else { 0 })
}

/*
pub fn gen_short_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i8!(x, *i)
}
*/

pub fn gen_short_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, *u)
}

/*
pub fn gen_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i16!(x, *i)
}
*/

pub fn gen_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u16!(x, *u)
}

/*
pub fn gen_long_int<'a>(x: (&'a mut [u8], usize), i: &LongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i32!(x, *i)
}
*/

pub fn gen_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u32!(x, *u)
}

/*
pub fn gen_long_long_int<'a>(x: (&'a mut [u8], usize), i: &LongLongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i64!(x, *i)
}
*/

pub fn gen_long_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongLongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u64!(x, *u)
}

/* TODO: Float, Double */

pub fn gen_decimal_value<'a>(x: (&'a mut [u8], usize), d: &DecimalValue) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u8!(d.scale) >> gen_be_u32!(d.value))
}

pub fn gen_short_string<'a>(x: (&'a mut [u8], usize), s: &ShortString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u8!(s.len() as u8) >> gen_slice!(s.as_bytes()))
}

pub fn gen_long_string<'a>(x: (&'a mut [u8], usize), s: &LongString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_be_u32!(s.len() as u32) >> gen_slice!(s.as_bytes()))
}

pub fn gen_field_array<'a>(x: (&'a mut [u8], usize), a: &FieldArray) -> Result<(&'a mut [u8], usize), GenError> {
    let (x1, index1) = x;
    gen_many_ref!((x1, index1 + 4), a, gen_value).and_then(|(x2, index2)| {
        gen_be_u32!((x2, index1), index2 - index1 - 4).and_then(|(x3, _)| Ok((x3, index2)))
    })
}

pub fn gen_timestamp<'a>(x: (&'a mut [u8], usize), t: &Timestamp) -> Result<(&'a mut [u8], usize), GenError> {
    gen_long_long_uint(x, t)
}

/* TODO: FieldTable */
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);

        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }

    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.x as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.y as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Accumulator     => { },
            AddressMode::Immediate       => { },
            AddressMode::Implied         => { },
            AddressMode::Indirect        => { },
            AddressMode::IndexedIndirect => { },
            AddressMode::IndirectIndexed => { },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {},
            AddressMode::ZeroPageY       => { },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }
}

<commit_msg>implemented Immediate addressing mode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);

        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }

    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.x as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.y as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Accumulator     => { },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Implied         => { },
            AddressMode::Indirect        => { },
            AddressMode::IndexedIndirect => { },
            AddressMode::IndirectIndexed => { },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {},
            AddressMode::ZeroPageY       => { },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }
}

<|endoftext|>


<commit_before>//! Eigenvalue decomposition for Hermite matrices

use ndarray::*;

use crate::diagonal::*;
use crate::error::*;
use crate::layout::*;
use crate::operator::LinearOperator;
use crate::types::*;
use crate::UPLO;

/// Eigenvalue decomposition of Hermite matrix reference
pub trait Eigh {
    type EigVal;
    type EigVec;
    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)>;
}

/// Eigenvalue decomposition of mutable reference of Hermite matrix
pub trait EighInplace {
    type EigVal;
    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)>;
}

/// Eigenvalue decomposition of Hermite matrix
pub trait EighInto: Sized {
    type EigVal;
    fn eigh_into(self, uplo: UPLO) -> Result<(Self::EigVal, Self)>;
}

impl<A, S> EighInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_into(mut self, uplo: UPLO) -> Result<(Self::EigVal, Self)> {
        let (val, _) = self.eigh_inplace(uplo)?;
        Ok((val, self))
    }
}

impl<A, S, S2> EighInto for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    S2: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_into(mut self, uplo: UPLO) -> Result<(Self::EigVal, Self)> {
        let (val, _) = self.eigh_inplace(uplo)?;
        Ok((val, self))
    }
}

impl<A, S> Eigh for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;
    type EigVec = Array2<A>;

    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)> {
        let a = self.to_owned();
        a.eigh_into(uplo)
    }
}

impl<A, S, S2> Eigh for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
    S2: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;
    type EigVec = (Array2<A>, Array2<A>);

    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)> {
        let (a, b) = (self.0.to_owned(), self.1.to_owned());
        (a, b).eigh_into(uplo)
    }
}

impl<A, S> EighInplace for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)> {
        let layout = self.square_layout()?;
        // XXX Force layout to be Fortran (see #146)
        match layout {
            MatrixLayout::C { .. } => self.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }
        let s = A::eigh(true, self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok((ArrayBase::from(s), self))
    }
}

impl<A, S, S2> EighInplace for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    S2: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)> {
        let layout = self.0.square_layout()?;
        // XXX Force layout to be Fortran (see #146)
        match layout {
            MatrixLayout::C { .. } => self.0.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }

        let layout = self.1.square_layout()?;
        match layout {
            MatrixLayout::C { .. } => self.1.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }

        let s = A::eigh_generalized(
            true,
            self.0.square_layout()?,
            uplo,
            self.0.as_allocated_mut()?,
            self.1.as_allocated_mut()?,
        )?;

        Ok((ArrayBase::from(s), self))
    }
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValsh {
    type EigVal;
    fn eigvalsh(&self, uplo: UPLO) -> Result<Self::EigVal>;
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValshInto {
    type EigVal;
    fn eigvalsh_into(self, uplo: UPLO) -> Result<Self::EigVal>;
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValshInplace {
    type EigVal;
    fn eigvalsh_inplace(&mut self, uplo: UPLO) -> Result<Self::EigVal>;
}

impl<A, S> EigValshInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh_into(mut self, uplo: UPLO) -> Result<Self::EigVal> {
        self.eigvalsh_inplace(uplo)
    }
}

impl<A, S> EigValsh for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh(&self, uplo: UPLO) -> Result<Self::EigVal> {
        let a = self.to_owned();
        a.eigvalsh_into(uplo)
    }
}

impl<A, S> EigValshInplace for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh_inplace(&mut self, uplo: UPLO) -> Result<Self::EigVal> {
        let s = A::eigh(true, self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(ArrayBase::from(s))
    }
}

/// Calculate symmetric square-root matrix using `eigh`
pub trait SymmetricSqrt {
    type Output;
    fn ssqrt(&self, uplo: UPLO) -> Result<Self::Output>;
}

impl<A, S> SymmetricSqrt for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type Output = Array2<A>;

    fn ssqrt(&self, uplo: UPLO) -> Result<Self::Output> {
        let a = self.to_owned();
        a.ssqrt_into(uplo)
    }
}

/// Calculate symmetric square-root matrix using `eigh`
pub trait SymmetricSqrtInto {
    type Output;
    fn ssqrt_into(self, uplo: UPLO) -> Result<Self::Output>;
}

impl<A, S> SymmetricSqrtInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A> + DataOwned,
{
    type Output = Array2<A>;

    fn ssqrt_into(self, uplo: UPLO) -> Result<Self::Output> {
        let (e, v) = self.eigh_into(uplo)?;
        let e_sqrt = Array::from_iter(e.iter().map(|r| Scalar::from_real(r.sqrt())));
        let ev = e_sqrt.into_diagonal().apply2(&v.t());
        Ok(v.apply2(&ev))
    }
}
<commit_msg>Add basic documentation for eigh<commit_after>//! Eigendecomposition for Hermitian matrices.
//!
//! For a Hermitian matrix `A`, this solves the eigenvalue problem `A V = V D`
//! for `D` and `V`, where `D` is the diagonal matrix of eigenvalues in
//! ascending order and `V` is the orthonormal matrix of corresponding
//! eigenvectors.
//!
//! For a pair of Hermitian matrices `A` and `B` where `B` is also positive
//! definite, this solves the generalized eigenvalue problem `A V = B V D`,
//! where `D` is the diagonal matrix of generalized eigenvalues in ascending
//! order and `V` is the matrix of corresponding generalized eigenvectors. The
//! matrix `V` is normalized such that `V^H B V = I`.

use ndarray::*;

use crate::diagonal::*;
use crate::error::*;
use crate::layout::*;
use crate::operator::LinearOperator;
use crate::types::*;
use crate::UPLO;

/// Eigenvalue decomposition of Hermite matrix reference
pub trait Eigh {
    type EigVal;
    type EigVec;
    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)>;
}

/// Eigenvalue decomposition of mutable reference of Hermite matrix
pub trait EighInplace {
    type EigVal;
    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)>;
}

/// Eigenvalue decomposition of Hermite matrix
pub trait EighInto: Sized {
    type EigVal;
    fn eigh_into(self, uplo: UPLO) -> Result<(Self::EigVal, Self)>;
}

impl<A, S> EighInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_into(mut self, uplo: UPLO) -> Result<(Self::EigVal, Self)> {
        let (val, _) = self.eigh_inplace(uplo)?;
        Ok((val, self))
    }
}

impl<A, S, S2> EighInto for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    S2: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_into(mut self, uplo: UPLO) -> Result<(Self::EigVal, Self)> {
        let (val, _) = self.eigh_inplace(uplo)?;
        Ok((val, self))
    }
}

impl<A, S> Eigh for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;
    type EigVec = Array2<A>;

    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)> {
        let a = self.to_owned();
        a.eigh_into(uplo)
    }
}

impl<A, S, S2> Eigh for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
    S2: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;
    type EigVec = (Array2<A>, Array2<A>);

    fn eigh(&self, uplo: UPLO) -> Result<(Self::EigVal, Self::EigVec)> {
        let (a, b) = (self.0.to_owned(), self.1.to_owned());
        (a, b).eigh_into(uplo)
    }
}

impl<A, S> EighInplace for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)> {
        let layout = self.square_layout()?;
        // XXX Force layout to be Fortran (see #146)
        match layout {
            MatrixLayout::C { .. } => self.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }
        let s = A::eigh(true, self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok((ArrayBase::from(s), self))
    }
}

impl<A, S, S2> EighInplace for (ArrayBase<S, Ix2>, ArrayBase<S2, Ix2>)
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    S2: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigh_inplace(&mut self, uplo: UPLO) -> Result<(Self::EigVal, &mut Self)> {
        let layout = self.0.square_layout()?;
        // XXX Force layout to be Fortran (see #146)
        match layout {
            MatrixLayout::C { .. } => self.0.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }

        let layout = self.1.square_layout()?;
        match layout {
            MatrixLayout::C { .. } => self.1.swap_axes(0, 1),
            MatrixLayout::F { .. } => {}
        }

        let s = A::eigh_generalized(
            true,
            self.0.square_layout()?,
            uplo,
            self.0.as_allocated_mut()?,
            self.1.as_allocated_mut()?,
        )?;

        Ok((ArrayBase::from(s), self))
    }
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValsh {
    type EigVal;
    fn eigvalsh(&self, uplo: UPLO) -> Result<Self::EigVal>;
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValshInto {
    type EigVal;
    fn eigvalsh_into(self, uplo: UPLO) -> Result<Self::EigVal>;
}

/// Calculate eigenvalues without eigenvectors
pub trait EigValshInplace {
    type EigVal;
    fn eigvalsh_inplace(&mut self, uplo: UPLO) -> Result<Self::EigVal>;
}

impl<A, S> EigValshInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh_into(mut self, uplo: UPLO) -> Result<Self::EigVal> {
        self.eigvalsh_inplace(uplo)
    }
}

impl<A, S> EigValsh for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh(&self, uplo: UPLO) -> Result<Self::EigVal> {
        let a = self.to_owned();
        a.eigvalsh_into(uplo)
    }
}

impl<A, S> EigValshInplace for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
{
    type EigVal = Array1<A::Real>;

    fn eigvalsh_inplace(&mut self, uplo: UPLO) -> Result<Self::EigVal> {
        let s = A::eigh(true, self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(ArrayBase::from(s))
    }
}

/// Calculate symmetric square-root matrix using `eigh`
pub trait SymmetricSqrt {
    type Output;
    fn ssqrt(&self, uplo: UPLO) -> Result<Self::Output>;
}

impl<A, S> SymmetricSqrt for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    type Output = Array2<A>;

    fn ssqrt(&self, uplo: UPLO) -> Result<Self::Output> {
        let a = self.to_owned();
        a.ssqrt_into(uplo)
    }
}

/// Calculate symmetric square-root matrix using `eigh`
pub trait SymmetricSqrtInto {
    type Output;
    fn ssqrt_into(self, uplo: UPLO) -> Result<Self::Output>;
}

impl<A, S> SymmetricSqrtInto for ArrayBase<S, Ix2>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A> + DataOwned,
{
    type Output = Array2<A>;

    fn ssqrt_into(self, uplo: UPLO) -> Result<Self::Output> {
        let (e, v) = self.eigh_into(uplo)?;
        let e_sqrt = Array::from_iter(e.iter().map(|r| Scalar::from_real(r.sqrt())));
        let ev = e_sqrt.into_diagonal().apply2(&v.t());
        Ok(v.apply2(&ev))
    }
}
<|endoftext|>


<commit_before>use pombase_rc_string::RcString;

use crate::web::config::Config;
use crate::web::data::{GeneDetails, ReferenceDetails, TermDetails,
                       ContainerType, GenotypeShort,
                       OntAnnotationId, AnnotationContainer, OrthologAnnotationContainer};

fn format_page(header: &str, body: &str) -> String {
    format! ("
<!DOCTYPE html>

    {}

    {}

",
             header, body)
}

fn make_gene_title(config: &Config, gene_details: &GeneDetails) -> String {
    let name_and_uniquename =
        if let Some(ref name) = gene_details.name {
            format!("{} ({})", name, gene_details.uniquename)
        } else {
            format!("{}", gene_details.uniquename)
        };

    let feature_type =
        if gene_details.feature_type.ends_with("gene") {
            String::from(gene_details.feature_type.as_str())
        } else {
            format!("{} gene", gene_details.feature_type)
        };

    if let Some(ref product) = gene_details.product {
        format!("{} - {} - {} - {}", config.database_name, feature_type,
                name_and_uniquename, product)
    } else {
        format!("{} - {} - {}", config.database_name, feature_type, name_and_uniquename)
    }
}

fn header(config: &Config, title: &str) -> String  {
    format!(r##"
  <meta charset="utf-8">
  <title>{}</title>
  <base href="/">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="title" content="{}">
  <meta name="author" content="{}">
  <meta name="description" content="{}">
  <meta name="google-site-verification" content="H8vhCdG7XsSbh-8f20VSipvu2PnZ22YSGZm81jE0-Pk" />
  <link rel="shortcut icon" href="/assets/favicon.ico">
  <meta name="apple-mobile-web-app-title" content="{}">
  <meta name="application-name" content="{}">
"##,
            title, title, config.database_name, title, config.database_name,
            config.database_name
    )
}

fn gene_summary(config: &Config, gene_details: &GeneDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";
    if let Some(ref name) = gene_details.name {
        summ += &format!("
Gene standard name

{}
\n",  name);
    }
    summ += &format!("
Systematic ID

{}
\n", gene_details.uniquename);

    if let Some(gene_organism) = config.organism_by_taxonid(gene_details.taxonid) {
        summ += &format!("
Organism

{}\n", gene_organism.scientific_name());

        if gene_organism.alternative_names.len() > 0 {
            summ += &format!(" ({})", gene_organism.alternative_names.join(", "));
        }
        summ += "
\n";
    }

    if gene_details.synonyms.len() > 0 {
        let synonyms: Vec<RcString> =
            gene_details.synonyms.iter().map(|s| s.name.clone()).collect();
        summ += &format!("
Synonyms

{}
\n", synonyms.join(", "));
    }

    if let Some(ref uniprot_identifier) = gene_details.uniprot_identifier {
        summ += &format!("
UniProt ID

{}
\n", uniprot_identifier);
    }

    if let Some(ref orfeome_identifier) = gene_details.orfeome_identifier {
        summ += &format!("
ORFeome ID

{}
\n", orfeome_identifier);
    }

    if let Some(ref characterisation_status) = gene_details.characterisation_status {
        summ += &format!("
Characterisation status

{}\n",
                         characterisation_status);
    }

    summ += "
\n";

    summ
}

fn genotype_display_name(genotype_short: &GenotypeShort) -> String {
    let mut bits: Vec<_> = genotype_short.display_uniquename.split("-").collect();
    bits.dedup();
    bits.join(" ")
}

fn get_annotations(ont_annotation_ids: &Vec<OntAnnotationId>,
                   container: &dyn AnnotationContainer) -> String {
    let mut ret = String::new();
    let mut references = vec![];
    let mut genes = vec![];
    let mut genotypes = vec![];

    for ont_annotation_id in ont_annotation_ids {
        if let Some(annotation_details) = container.annotation_details().get(ont_annotation_id) {
            if let Some(ref reference) = annotation_details.reference {
                references.push(reference);
            }

            if let Some(ref genotype) = annotation_details.genotype {
                genotypes.push(genotype);
            }

            for gene_uniquename in &annotation_details.genes {
                if let Some(maybe_gene_short) =
                    container.genes_by_uniquename().get(gene_uniquename.as_str()) {
                        if let Some(gene_short) = maybe_gene_short {
                            genes.push(gene_short)
                        }
                    }
            }
        }
    }

    if container.container_type() != ContainerType::Reference && references.len() > 0 {
        references.sort();
        references.dedup();
        ret += "
References:
\n
";
        for reference in references {
            ret += &format!("
{}
\n", reference, reference);
        }
        ret += "
\n";
    }

    if container.container_type() != ContainerType::Gene && genes.len() > 0 {
        genes.sort();
        genes.dedup();
        ret += "
Genes:
\n
";
        for gene in genes {
            ret += &format!("
{}
\n", gene.uniquename,
                            gene.display_name());
        }
        ret += "
\n";
    }

    if container.container_type() != ContainerType::Genotype && genotypes.len() > 0 {
        genotypes.sort();
        genotypes.dedup();
        if let Some(genotypes_by_uniquename) = container.genotypes_by_uniquename() {
            ret += "
Genotypes:
\n
";
            for uniquename in genotypes {
                if let Some(genotype_short) = genotypes_by_uniquename.get(uniquename.as_str()) {
                    ret += &format!("
{}
\n",
                                    uniquename,
                                    genotype_display_name(genotype_short));
                }
            }
            ret += "
\n";
        }
    }

    ret
}

fn annotation_section(config: &Config, container: &dyn AnnotationContainer) -> String {
    let mut annotation_html = String::new();

    let mut cv_names: Vec<RcString> = vec![];

    for cv_name in container.cv_annotations().keys() {
        cv_names.push(cv_name.clone());
    }

    let cmp_display_names =
        |cv_name_a: &RcString, cv_name_b: &RcString| {
            let cv_config_a = config.cv_config_by_name(&cv_name_a);
            let cv_display_name_a = cv_config_a.display_name;
            let cv_config_b = config.cv_config_by_name(&cv_name_b);
            let cv_display_name_b = cv_config_b.display_name;

            cv_display_name_a.cmp(&cv_display_name_b)
        };

    cv_names.sort_by(cmp_display_names);

    for cv_name in cv_names {
        let term_annotations = container.cv_annotations().get(&cv_name).unwrap();
        let cv_config = config.cv_config_by_name(&cv_name);

        if let Some(cv_display_name) = cv_config.display_name {
            annotation_html += &format!("<sect>\n
{}
\n", cv_display_name);
            for term_annotation in term_annotations {
                let term_name =
                    if let Some(term_short_opt) =
                    container.terms_by_termid().get(&term_annotation.term) {
                        if let Some(term_short) = term_short_opt {
                            String::from(term_short.name.as_str())
                        } else {
                            String::from("(unknown term name)")
                        }
                    } else {
                        String::from("(unknown term name)")
                    };
                annotation_html += &format!("<sect>
{} - \
                                             {}
\n{}</sect>\n",
                                            term_annotation.term,
                                            term_annotation.term,
                                            term_annotation.term,
                                            term_name,
                                            get_annotations(&term_annotation.annotations,
                                                            container));
            }
            annotation_html += "</sect>\n";
        }
    }

    annotation_html
}

fn orthologs(config: &Config, container: &dyn OrthologAnnotationContainer) -> String {
    let mut orth_html = String::new();

    if container.ortholog_annotations().is_empty() {
        return orth_html;
    }

    orth_html += "<sect>
Orthologs
\n
\n";

    for orth_annotation in container.ortholog_annotations().iter() {
        let maybe_orth_org = config.organism_by_taxonid(orth_annotation.ortholog_taxonid);
        let orth_org_scientific_name =
            if let Some(orth_org) = maybe_orth_org {
                orth_org.scientific_name()
            } else {
                String::from("Unknown organism")
            };
        if let Some(maybe_orth_gene_short) =
            container.genes_by_uniquename().get(&orth_annotation.ortholog_uniquename) {
                if let Some(orth_gene_short) = maybe_orth_gene_short {
                    orth_html += &format!("
{} {}
\n", orth_gene_short.display_name(),
                                          orth_org_scientific_name);
                }
            }
    }

    orth_html += "
</sect>\n";

    orth_html
}

fn gene_body(config: &Config, title: &str, gene_details: &GeneDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Gene summary
\n{}</sect>\n",
                     gene_summary(config, gene_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, gene_details));

    body += &orthologs(config, gene_details);

    body
}

pub fn render_simple_gene_page(config: &Config, gene_details: &GeneDetails) -> String  {
    let title = make_gene_title(config, gene_details);

    format_page(&header(config, &title), &gene_body(config, &title, gene_details))
}

fn make_reference_title(config: &Config, reference_details: &ReferenceDetails) -> String {
    if let Some(ref title) = reference_details.title {
        format!("{} - Reference - {} - {}", config.database_name, reference_details.uniquename, title)
    } else {
        format!("{} - Reference - {}", config.database_name, reference_details.uniquename)
    }
}

fn reference_summary(reference_details: &ReferenceDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";

    summ += &format!("
PubMed ID

{}
\n", reference_details.uniquename);

    if let Some(ref title) = reference_details.title {
        summ += &format!("
Title

{}
\n", title);
    }

    if let Some(ref authors) = reference_details.authors {
        summ += &format!("
Authors

{}
\n", authors);
    }

    if let Some(ref citation) = reference_details.citation {
        summ += &format!("
Citation

{}
\n", citation);
    }

    if let Some(ref publication_year) = reference_details.publication_year {
        summ += &format!("
Publication year

{}
\n", publication_year);
    }

    summ += "
\n";

    summ
}

fn reference_body(config: &Config, title: &str, reference_details: &ReferenceDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Reference summary
\n{}</sect>\n",
                     reference_summary(reference_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, reference_details));

    body += &orthologs(config, reference_details);

    body
}

pub fn render_simple_reference_page(config: &Config, reference_details: &ReferenceDetails) -> String  {
    let title = make_reference_title(config, reference_details);

    format_page(&header(config, &title), &reference_body(config, &title, reference_details))
}

fn make_term_title(config: &Config, term_details: &TermDetails) -> String {
    let cv_config = config.cv_config_by_name(&term_details.cv_name);
    let cv_display_name = cv_config.display_name.unwrap_or_else(|| RcString::from("DEFAULT"));

    format!("{} - Term - {} - {} - {}", config.database_name, term_details.termid,
            term_details.name, cv_display_name)
}

fn term_summary(config: &Config, term_details: &TermDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";

    summ += &format!("
Term ID

{}
\n", term_details.termid);
    summ += &format!("
Term name

{}
\n", term_details.name);

    let cv_config = config.cv_config_by_name(&term_details.cv_name);
    let cv_display_name = cv_config.display_name.unwrap_or_else(|| RcString::from("DEFAULT"));

    summ += &format!("
CV name

{}
\n", cv_display_name);

    summ += "
\n";

    summ
}

fn term_body(config: &Config, title: &str, term_details: &TermDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Term summary
\n{}</sect>\n",
                     term_summary(config, term_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, term_details));

    body
}

pub fn render_simple_term_page(config: &Config, term_details: &TermDetails) -> String  {
    let title = make_term_title(config, term_details);

    format_page(&header(config, &title), &term_body(config, &title, term_details))
}
<commit_msg>Use "protein coding gene" in simple page titles<commit_after>use pombase_rc_string::RcString;

use crate::web::config::Config;
use crate::web::data::{GeneDetails, ReferenceDetails, TermDetails,
                       ContainerType, GenotypeShort,
                       OntAnnotationId, AnnotationContainer, OrthologAnnotationContainer};

fn format_page(header: &str, body: &str) -> String {
    format! ("
<!DOCTYPE html>

    {}

    {}

",
             header, body)
}

fn make_gene_title(config: &Config, gene_details: &GeneDetails) -> String {
    let name_and_uniquename =
        if let Some(ref name) = gene_details.name {
            format!("{} ({})", name, gene_details.uniquename)
        } else {
            format!("{}", gene_details.uniquename)
        };

    let feature_type =
        if gene_details.feature_type == "mRNA gene" {
            String::from("protein coding gene")
        } else {
            if gene_details.feature_type.ends_with("gene") {
                String::from(gene_details.feature_type.as_str())
            } else {
                format!("{} gene", gene_details.feature_type)
            }
        };

    if let Some(ref product) = gene_details.product {
        format!("{} - {} - {} - {}", config.database_name, feature_type,
                name_and_uniquename, product)
    } else {
        format!("{} - {} - {}", config.database_name, feature_type, name_and_uniquename)
    }
}

fn header(config: &Config, title: &str) -> String  {
    format!(r##"
  <meta charset="utf-8">
  <title>{}</title>
  <base href="/">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="title" content="{}">
  <meta name="author" content="{}">
  <meta name="description" content="{}">
  <meta name="google-site-verification" content="H8vhCdG7XsSbh-8f20VSipvu2PnZ22YSGZm81jE0-Pk" />
  <link rel="shortcut icon" href="/assets/favicon.ico">
  <meta name="apple-mobile-web-app-title" content="{}">
  <meta name="application-name" content="{}">
"##,
            title, title, config.database_name, title, config.database_name,
            config.database_name
    )
}

fn gene_summary(config: &Config, gene_details: &GeneDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";
    if let Some(ref name) = gene_details.name {
        summ += &format!("
Gene standard name

{}
\n",  name);
    }
    summ += &format!("
Systematic ID

{}
\n", gene_details.uniquename);

    if let Some(gene_organism) = config.organism_by_taxonid(gene_details.taxonid) {
        summ += &format!("
Organism

{}\n", gene_organism.scientific_name());

        if gene_organism.alternative_names.len() > 0 {
            summ += &format!(" ({})", gene_organism.alternative_names.join(", "));
        }
        summ += "
\n";
    }

    if gene_details.synonyms.len() > 0 {
        let synonyms: Vec<RcString> =
            gene_details.synonyms.iter().map(|s| s.name.clone()).collect();
        summ += &format!("
Synonyms

{}
\n", synonyms.join(", "));
    }

    if let Some(ref uniprot_identifier) = gene_details.uniprot_identifier {
        summ += &format!("
UniProt ID

{}
\n", uniprot_identifier);
    }

    if let Some(ref orfeome_identifier) = gene_details.orfeome_identifier {
        summ += &format!("
ORFeome ID

{}
\n", orfeome_identifier);
    }

    if let Some(ref characterisation_status) = gene_details.characterisation_status {
        summ += &format!("
Characterisation status

{}\n",
                         characterisation_status);
    }

    summ += "
\n";

    summ
}

fn genotype_display_name(genotype_short: &GenotypeShort) -> String {
    let mut bits: Vec<_> = genotype_short.display_uniquename.split("-").collect();
    bits.dedup();
    bits.join(" ")
}

fn get_annotations(ont_annotation_ids: &Vec<OntAnnotationId>,
                   container: &dyn AnnotationContainer) -> String {
    let mut ret = String::new();
    let mut references = vec![];
    let mut genes = vec![];
    let mut genotypes = vec![];

    for ont_annotation_id in ont_annotation_ids {
        if let Some(annotation_details) = container.annotation_details().get(ont_annotation_id) {
            if let Some(ref reference) = annotation_details.reference {
                references.push(reference);
            }

            if let Some(ref genotype) = annotation_details.genotype {
                genotypes.push(genotype);
            }

            for gene_uniquename in &annotation_details.genes {
                if let Some(maybe_gene_short) =
                    container.genes_by_uniquename().get(gene_uniquename.as_str()) {
                        if let Some(gene_short) = maybe_gene_short {
                            genes.push(gene_short)
                        }
                    }
            }
        }
    }

    if container.container_type() != ContainerType::Reference && references.len() > 0 {
        references.sort();
        references.dedup();
        ret += "
References:
\n
";
        for reference in references {
            ret += &format!("
{}
\n", reference, reference);
        }
        ret += "
\n";
    }

    if container.container_type() != ContainerType::Gene && genes.len() > 0 {
        genes.sort();
        genes.dedup();
        ret += "
Genes:
\n
";
        for gene in genes {
            ret += &format!("
{}
\n", gene.uniquename,
                            gene.display_name());
        }
        ret += "
\n";
    }

    if container.container_type() != ContainerType::Genotype && genotypes.len() > 0 {
        genotypes.sort();
        genotypes.dedup();
        if let Some(genotypes_by_uniquename) = container.genotypes_by_uniquename() {
            ret += "
Genotypes:
\n
";
            for uniquename in genotypes {
                if let Some(genotype_short) = genotypes_by_uniquename.get(uniquename.as_str()) {
                    ret += &format!("
{}
\n",
                                    uniquename,
                                    genotype_display_name(genotype_short));
                }
            }
            ret += "
\n";
        }
    }

    ret
}

fn annotation_section(config: &Config, container: &dyn AnnotationContainer) -> String {
    let mut annotation_html = String::new();

    let mut cv_names: Vec<RcString> = vec![];

    for cv_name in container.cv_annotations().keys() {
        cv_names.push(cv_name.clone());
    }

    let cmp_display_names =
        |cv_name_a: &RcString, cv_name_b: &RcString| {
            let cv_config_a = config.cv_config_by_name(&cv_name_a);
            let cv_display_name_a = cv_config_a.display_name;
            let cv_config_b = config.cv_config_by_name(&cv_name_b);
            let cv_display_name_b = cv_config_b.display_name;

            cv_display_name_a.cmp(&cv_display_name_b)
        };

    cv_names.sort_by(cmp_display_names);

    for cv_name in cv_names {
        let term_annotations = container.cv_annotations().get(&cv_name).unwrap();
        let cv_config = config.cv_config_by_name(&cv_name);

        if let Some(cv_display_name) = cv_config.display_name {
            annotation_html += &format!("<sect>\n
{}
\n", cv_display_name);
            for term_annotation in term_annotations {
                let term_name =
                    if let Some(term_short_opt) =
                    container.terms_by_termid().get(&term_annotation.term) {
                        if let Some(term_short) = term_short_opt {
                            String::from(term_short.name.as_str())
                        } else {
                            String::from("(unknown term name)")
                        }
                    } else {
                        String::from("(unknown term name)")
                    };
                annotation_html += &format!("<sect>
{} - \
                                             {}
\n{}</sect>\n",
                                            term_annotation.term,
                                            term_annotation.term,
                                            term_annotation.term,
                                            term_name,
                                            get_annotations(&term_annotation.annotations,
                                                            container));
            }
            annotation_html += "</sect>\n";
        }
    }

    annotation_html
}

fn orthologs(config: &Config, container: &dyn OrthologAnnotationContainer) -> String {
    let mut orth_html = String::new();

    if container.ortholog_annotations().is_empty() {
        return orth_html;
    }

    orth_html += "<sect>
Orthologs
\n
\n";

    for orth_annotation in container.ortholog_annotations().iter() {
        let maybe_orth_org = config.organism_by_taxonid(orth_annotation.ortholog_taxonid);
        let orth_org_scientific_name =
            if let Some(orth_org) = maybe_orth_org {
                orth_org.scientific_name()
            } else {
                String::from("Unknown organism")
            };
        if let Some(maybe_orth_gene_short) =
            container.genes_by_uniquename().get(&orth_annotation.ortholog_uniquename) {
                if let Some(orth_gene_short) = maybe_orth_gene_short {
                    orth_html += &format!("
{} {}
\n", orth_gene_short.display_name(),
                                          orth_org_scientific_name);
                }
            }
    }

    orth_html += "
</sect>\n";

    orth_html
}

fn gene_body(config: &Config, title: &str, gene_details: &GeneDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Gene summary
\n{}</sect>\n",
                     gene_summary(config, gene_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, gene_details));

    body += &orthologs(config, gene_details);

    body
}

pub fn render_simple_gene_page(config: &Config, gene_details: &GeneDetails) -> String  {
    let title = make_gene_title(config, gene_details);

    format_page(&header(config, &title), &gene_body(config, &title, gene_details))
}

fn make_reference_title(config: &Config, reference_details: &ReferenceDetails) -> String {
    if let Some(ref title) = reference_details.title {
        format!("{} - Reference - {} - {}", config.database_name, reference_details.uniquename, title)
    } else {
        format!("{} - Reference - {}", config.database_name, reference_details.uniquename)
    }
}

fn reference_summary(reference_details: &ReferenceDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";

    summ += &format!("
PubMed ID

{}
\n", reference_details.uniquename);

    if let Some(ref title) = reference_details.title {
        summ += &format!("
Title

{}
\n", title);
    }

    if let Some(ref authors) = reference_details.authors {
        summ += &format!("
Authors

{}
\n", authors);
    }

    if let Some(ref citation) = reference_details.citation {
        summ += &format!("
Citation

{}
\n", citation);
    }

    if let Some(ref publication_year) = reference_details.publication_year {
        summ += &format!("
Publication year

{}
\n", publication_year);
    }

    summ += "
\n";

    summ
}

fn reference_body(config: &Config, title: &str, reference_details: &ReferenceDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Reference summary
\n{}</sect>\n",
                     reference_summary(reference_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, reference_details));

    body += &orthologs(config, reference_details);

    body
}

pub fn render_simple_reference_page(config: &Config, reference_details: &ReferenceDetails) -> String  {
    let title = make_reference_title(config, reference_details);

    format_page(&header(config, &title), &reference_body(config, &title, reference_details))
}

fn make_term_title(config: &Config, term_details: &TermDetails) -> String {
    let cv_config = config.cv_config_by_name(&term_details.cv_name);
    let cv_display_name = cv_config.display_name.unwrap_or_else(|| RcString::from("DEFAULT"));

    format!("{} - Term - {} - {} - {}", config.database_name, term_details.termid,
            term_details.name, cv_display_name)
}

fn term_summary(config: &Config, term_details: &TermDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";

    summ += &format!("
Term ID

{}
\n", term_details.termid);
    summ += &format!("
Term name

{}
\n", term_details.name);

    let cv_config = config.cv_config_by_name(&term_details.cv_name);
    let cv_display_name = cv_config.display_name.unwrap_or_else(|| RcString::from("DEFAULT"));

    summ += &format!("
CV name

{}
\n", cv_display_name);

    summ += "
\n";

    summ
}

fn term_body(config: &Config, title: &str, term_details: &TermDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to {}
\n
{}
</sect>\n",
                     config.database_name, config.site_description);

    body += &format!("<sect>
Term summary
\n{}</sect>\n",
                     term_summary(config, term_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     annotation_section(config, term_details));

    body
}

pub fn render_simple_term_page(config: &Config, term_details: &TermDetails) -> String  {
    let title = make_term_title(config, term_details);

    format_page(&header(config, &title), &term_body(config, &title, term_details))
}
<|endoftext|>


<commit_before>use rand::Rng;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// Distribution is trait that should be implemented
/// by structs that represent a statistical distribution
pub trait Distribution {
    /// Draws a random sample according to the distribution
    /// and the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// Univariate should be implemented by structs
/// representing a univariate statistical distribution.
pub trait Univariate : Distribution {
    fn mean(&self) -> f64;
    fn variance(&self) -> f64;
    fn std_dev(&self) -> f64;
    fn entropy(&self) -> f64;
    fn skewness(&self) -> f64;
    fn median(&self) -> f64;
    fn cdf(&self, x: f64) -> f64;
}

/// Continuous should be implemented by structs
/// representing a continuous univariate statistical
/// distribution
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// Discrete should be implemented by structs
/// representing a discrete univariate statistical
/// distribution
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}
<commit_msg>introduce checked interfaces, begin documentation of distribution traits<commit_after>use rand::Rng;
use super::result::Result;

pub use self::bernoulli::Bernoulli;
pub use self::binomial::Binomial;
pub use self::chi::Chi;
pub use self::chi_squared::ChiSquared;
pub use self::discrete_uniform::DiscreteUniform;
pub use self::exponential::Exponential;
pub use self::gamma::Gamma;
pub use self::log_normal::LogNormal;
pub use self::normal::Normal;
pub use self::poisson::Poisson;
pub use self::student_t::StudentT;
pub use self::triangular::Triangular;
pub use self::uniform::Uniform;
pub use self::weibull::Weibull;

mod bernoulli;
mod binomial;
mod chi;
mod chi_squared;
mod discrete_uniform;
mod exponential;
mod gamma;
mod log_normal;
mod normal;
mod poisson;
mod student_t;
mod triangular;
mod uniform;
mod weibull;

/// The `Distribution` trait is used to specify an interface
/// for sampling distributions
///
/// # Examples
///
/// A trivial implementation that just samples from the supplied
/// random number generator
///
/// ```
/// use rand::StdRng;
///
/// struct Foo;
///
/// impl Distribution for Foo {
///     fn sample<R: Rng>(&self, r: &mut R) -> f64 {
///         r.next_f64()
///     }
/// }
/// ```
pub trait Distribution {
    /// Draws a random sample using the supplied random number generator
    fn sample<R: Rng>(&self, r: &mut R) -> f64;
}

/// The `Univariate` trait extends the `Distribution`
/// trait provides an interface for interacting with
/// univariate statistical distributions.
///
/// # Remarks
///
/// All methods provided by the `Univariate` trait are unchecked, meaning
/// they will panic if in an invalid state or encountering invalid input
/// depending on the implementing Distribution. The `CheckedUnivariate`
/// trait provides a panic-safe interface for univariate distributions
pub trait Univariate : Distribution {
    fn mean(&self) -> f64;
    fn variance(&self) -> f64;
    fn std_dev(&self) -> f64;
    fn entropy(&self) -> f64;
    fn skewness(&self) -> f64;
    fn median(&self) -> f64;
    fn cdf(&self, x: f64) -> f64;
}

/// The `CheckedUnivariate` trait extends the `Distribution` trait and
/// provides a checked interface for interacting with univariate statistical
/// distributions. This means implementors should return an `Err` instead of
/// panicking on an invalid state or input.
pub trait CheckedUnivariate : Distribution {
    fn mean(&self) -> Result<f64>;
    fn variance(&self) -> Result<f64>;
    fn std_dev(&self) -> Result<f64>;
    fn entropy(&self) -> Result<f64>;
    fn skewness(&self) -> Result<f64>;
    fn median(&self) -> Result<f64>;
    fn cdf(&self) -> Result<f64>;
}

/// The `Continuous` trait extends the `Univariate`
/// trait and provides an interface for interacting with continuous
/// univariate statistical distributions
pub trait Continuous : Univariate {
    fn mode(&self) -> f64;
    fn min(&self) -> f64;
    fn max(&self) -> f64;
    fn pdf(&self, x: f64) -> f64;
    fn ln_pdf(&self, x: f64) -> f64;
}

/// The `CheckedContinous` trait extendds the `CheckedUnivariate`
/// trait and provides a checked interface for interacting with
/// continous univariate statistical distributions. This means
/// implementors should return an `Err` instead of panicking on
/// an invalid state or input.
pub trait CheckedContinuous : CheckedUnivariate {
    fn mode(&self) -> Result<f64>;
    fn min(&self) -> Result<f64>;
    fn max(&self) -> Result<f64>;
    fn pdf(&self, x: f64) -> Result<f64>;
    fn ln_pdf(&self, x: f64) -> Result<f64>;
}

/// The `Discrete` trait extends the `Univariate`
/// trait and provides an interface for interacting with discrete
/// univariate statistical distributions
pub trait Discrete : Univariate {
    fn mode(&self) -> i64;
    fn min(&self) -> i64;
    fn max(&self) -> i64;
    fn pmf(&self, x: i64) -> f64;
    fn ln_pmf(&self, x: i64) -> f64;
}

/// The `CheckedDiscrete` trait extends the `CheckedUnivariate` trait
/// and provides a checked interface for interacting with discrete
/// univariate statistical distributions. This means implementors
/// should return an `Err` instead of panicking on an invalid state
/// or input
pub trait CheckedDiscrete : CheckedUnivariate {
    fn mode(&self) -> Result<i64>;
    fn min(&self) -> Result<i64>;
    fn max(&self) -> Result<i64>;
    fn pmf(&self, x: i64) -> Result<f64>;
    fn ln_pmf(&self, x: i64) -> Result<f64>;
}<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(Debug, EnumMap, PartialEq)]
enum Discriminants {
    A = 2,
    B = 0,
    C = 1,
}

#[test]
fn discriminants() {
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.into_iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}
<commit_msg>Make discriminant test values huge to make mistakes more apparent<commit_after>#![no_std]

#[macro_use]
extern crate enum_map;

use enum_map::EnumMap;

#[derive(Debug, EnumMap, PartialEq)]
enum Discriminants {
    A = 2000,
    B = 3000,
    C = 1000,
}

#[test]
fn discriminants() {
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.into_iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}
<|endoftext|>


<commit_before>use parking_lot::{Mutex, MutexGuard};
use std::ops::{Deref, DerefMut};

use crate::gc::Address;
use crate::object::{Obj, Ref};
use crate::threads::current_thread;

pub const HANDLE_SIZE: usize = 256;

pub struct HandleMemory {
    inner: Mutex<HandleMemoryInner>,
}

impl HandleMemory {
    pub fn new() -> HandleMemory {
        HandleMemory {
            inner: Mutex::new(HandleMemoryInner::new()),
        }
    }

    pub fn handle<T>(&self, obj: Ref<T>) -> Handle<T> {
        self.inner.lock().handle(obj)
    }

    pub fn push_border(&self) {
        self.inner.lock().push_border();
    }

    pub fn pop_border(&self) {
        self.inner.lock().pop_border();
    }

    pub fn iter(&self) -> HandleMemoryIter {
        let inner = self.inner.lock();
        let len = inner.buffers.len();
        let free = inner.free;

        HandleMemoryIter {
            mem: inner,
            buffer_idx: 0,
            element_idx: 0,
            full_buffer_len: if len == 0 { 0 } else { len - 1 },
            last_buffer_len: free,
        }
    }
}

pub struct HandleMemoryInner {
    /// all buffers, Box is important since HandleBuffer
    /// is a big struct that needs to get moved/copied on resizes
    buffers: Vec<Box<HandleBuffer>>,

    // store addresses of inserted borders
    borders: Vec<BorderData>,

    // index of next free position in buffer
    free: usize,
}

impl HandleMemoryInner {
    pub fn new() -> HandleMemoryInner {
        let buffer = Box::new(HandleBuffer::new());

        HandleMemoryInner {
            buffers: vec![buffer],
            borders: Vec::new(),
            free: 0,
        }
    }

    pub fn handle<T>(&mut self, obj: Ref<T>) -> Handle<T> {
        debug_assert!(current_thread().is_running());

        if self.free >= HANDLE_SIZE {
            self.push_buffer();
            self.free = 0;
        }

        let buffer = self.buffers.last_mut().unwrap();

        let idx = self.free;
        let elem = &mut buffer.elements[idx];
        self.free = idx + 1;

        *elem = obj.cast::<Obj>();

        Handle(elem as *mut Ref<Obj> as *mut Ref<T>)
    }

    pub fn push_buffer(&mut self) {
        self.buffers.push(Box::new(HandleBuffer::new()));
    }

    pub fn push_border(&mut self) {
        let buffer = self.buffers.len();
        let element = self.free;

        self.borders.push(BorderData { buffer, element });
    }

    pub fn pop_border(&mut self) {
        let border = self.borders.pop().expect("no border left");

        self.buffers.truncate(border.buffer);
        self.free = border.element;
    }
}

pub fn handle<T>(obj: Ref<T>) -> Handle<T> {
    let thread = current_thread();
    debug_assert!(thread.state_relaxed().is_running());
    thread.handles.handle(obj)
}

struct HandleBuffer {
    elements: [Ref<Obj>; HANDLE_SIZE],
}

impl HandleBuffer {
    fn new() -> HandleBuffer {
        HandleBuffer {
            elements: [Ref::null(); HANDLE_SIZE],
        }
    }
}

struct BorderData {
    buffer: usize,
    element: usize,
}
#[repr(C)]
pub struct Handle<T>(*mut Ref<T>);

impl<T> Handle<T> {
    pub fn direct(self) -> Ref<T> {
        debug_assert!(current_thread().is_running());
        unsafe { *self.0 }
    }

    pub fn direct_ptr(self) -> Address {
        debug_assert!(current_thread().is_running());
        unsafe { *self.0 }.address()
    }

    pub fn location(&self) -> Address {
        Address::from_ptr(self.0)
    }

    pub fn from_address(location: Address) -> Handle<T> {
        Handle(location.to_mut_ptr())
    }

    pub fn cast<R>(self) -> Handle<R> {
        Handle(self.0 as *mut Ref<R>)
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        debug_assert!(current_thread().is_running());
        unsafe { &*self.0 }.deref()
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        debug_assert!(current_thread().is_running());
        unsafe { &mut *self.0 }.deref_mut()
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

pub struct HandleMemoryIter<'a> {
    mem: MutexGuard<'a, HandleMemoryInner>,
    buffer_idx: usize,
    element_idx: usize,
    full_buffer_len: usize,
    last_buffer_len: usize,
}

impl<'a> Iterator for HandleMemoryIter<'a> {
    type Item = Handle<Obj>;

    fn next(&mut self) -> Option<Handle<Obj>> {
        while self.buffer_idx < self.full_buffer_len {
            if self.element_idx < HANDLE_SIZE {
                let idx = self.element_idx;
                self.element_idx += 1;

                let buffer = &mut self.mem.buffers[self.buffer_idx];
                return Some(Handle(&mut buffer.elements[idx] as *mut Ref<Obj>));
            } else {
                self.buffer_idx += 1;
                self.element_idx = 0;
            }
        }

        if self.buffer_idx == self.full_buffer_len {
            if self.element_idx < self.last_buffer_len {
                let idx = self.element_idx;
                self.element_idx += 1;

                let buffer = &mut self.mem.buffers[self.buffer_idx];
                Some(Handle(&mut buffer.elements[idx] as *mut Ref<Obj>))
            } else {
                None
            }
        } else {
            None
        }
    }
}

pub fn handle_scope<F: FnOnce() -> R, R>(f: F) -> R {
    let thread = current_thread();
    thread.handles.push_border();
    let result = f();
    thread.handles.pop_border();
    result
}
<commit_msg>add test for handle iteration<commit_after>use parking_lot::{Mutex, MutexGuard};
use std::ops::{Deref, DerefMut};

use crate::gc::Address;
use crate::object::{Obj, Ref};
use crate::threads::current_thread;

pub const HANDLE_BLOCK_SIZE: usize = 256;

pub struct HandleMemory {
    inner: Mutex<HandleMemoryInner>,
}

impl HandleMemory {
    pub fn new() -> HandleMemory {
        HandleMemory {
            inner: Mutex::new(HandleMemoryInner::new()),
        }
    }

    pub fn handle<T>(&self, obj: Ref<T>) -> Handle<T> {
        debug_assert!(current_thread().is_running());
        let address = self.inner.lock().handle(obj.address());
        Handle(address.to_mut_ptr())
    }

    #[cfg(test)]
    fn handle_address(&self, object_address: Address) {
        self.inner.lock().handle(object_address);
    }

    pub fn push_border(&self) {
        self.inner.lock().push_border();
    }

    pub fn pop_border(&self) {
        self.inner.lock().pop_border();
    }

    pub fn iter(&self) -> HandleMemoryIter {
        let inner = self.inner.lock();
        let len = inner.blocks.len();
        let free = inner.free;

        HandleMemoryIter {
            mem: inner,
            block_idx: 0,
            element_idx: 0,
            filled_blocks: if len == 0 { 0 } else { len - 1 },
            handles_in_last_block: free,
        }
    }
}

pub struct HandleMemoryInner {
    /// All blocks, Box is important since HandleBlock
    /// is a big struct that needs to get moved/copied on resizes.
    blocks: Vec<Box<HandleBlock>>,

    // Store addresses of inserted borders.
    borders: Vec<BorderData>,

    // Index of next free position in block.
    free: usize,
}

impl HandleMemoryInner {
    pub fn new() -> HandleMemoryInner {
        let initial_block = Box::new(HandleBlock::new());

        HandleMemoryInner {
            blocks: vec![initial_block],
            borders: Vec::new(),
            free: 0,
        }
    }

    pub fn handle(&mut self, object_address: Address) -> Address {
        if self.free >= HANDLE_BLOCK_SIZE {
            self.push_block();
            self.free = 0;
        }

        let block = self.blocks.last_mut().unwrap();

        let idx = self.free;
        let elem = &mut block.elements[idx];
        self.free = idx + 1;

        *elem = object_address;

        Address::from_ptr(elem)
    }

    fn push_block(&mut self) {
        self.blocks.push(Box::new(HandleBlock::new()));
    }

    pub fn push_border(&mut self) {
        let blocks = self.blocks.len();
        let element = self.free;

        self.borders.push(BorderData { blocks, element });
    }

    pub fn pop_border(&mut self) {
        let border = self.borders.pop().expect("no border left");

        self.blocks.truncate(border.blocks);
        self.free = border.element;
    }
}

pub fn handle<T>(obj: Ref<T>) -> Handle<T> {
    let thread = current_thread();
    debug_assert!(thread.state_relaxed().is_running());
    thread.handles.handle(obj)
}

struct HandleBlock {
    elements: [Address; HANDLE_BLOCK_SIZE],
}

impl HandleBlock {
    fn new() -> HandleBlock {
        HandleBlock {
            elements: [Address::null(); HANDLE_BLOCK_SIZE],
        }
    }
}

struct BorderData {
    blocks: usize,
    element: usize,
}
#[repr(C)]
pub struct Handle<T>(*mut Ref<T>);

impl<T> Handle<T> {
    pub fn direct(self) -> Ref<T> {
        debug_assert!(current_thread().is_running());
        unsafe { *self.0 }
    }

    pub fn direct_ptr(self) -> Address {
        debug_assert!(current_thread().is_running());
        self.raw_load()
    }

    // Internal method for dereferencing this handle, does not
    // check thread on purpose for testing purposes.
    fn raw_load(self) -> Address {
        unsafe { *self.0 }.address()
    }

    pub fn location(&self) -> Address {
        Address::from_ptr(self.0)
    }

    pub fn from_address(location: Address) -> Handle<T> {
        Handle(location.to_mut_ptr())
    }

    pub fn cast<R>(self) -> Handle<R> {
        Handle(self.0 as *mut Ref<R>)
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        debug_assert!(current_thread().is_running());
        unsafe { &*self.0 }.deref()
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        debug_assert!(current_thread().is_running());
        unsafe { &mut *self.0 }.deref_mut()
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

pub struct HandleMemoryIter<'a> {
    mem: MutexGuard<'a, HandleMemoryInner>,
    block_idx: usize,
    element_idx: usize,
    filled_blocks: usize,
    handles_in_last_block: usize,
}

impl<'a> Iterator for HandleMemoryIter<'a> {
    type Item = Handle<Obj>;

    fn next(&mut self) -> Option<Handle<Obj>> {
        if self.element_idx == HANDLE_BLOCK_SIZE {
            self.block_idx += 1;
            self.element_idx = 0;
        }

        if (self.block_idx < self.filled_blocks)
            || (self.block_idx == self.filled_blocks
                && self.element_idx < self.handles_in_last_block)
        {
            let idx = self.element_idx;
            self.element_idx += 1;

            let block = &self.mem.blocks[self.block_idx];
            return Some(Handle::from_address(Address::from_ptr(
                &block.elements[idx],
            )));
        } else {
            None
        }
    }
}

#[test]
fn test_handle_iteration() {
    let sizes = [
        0,
        4,
        HANDLE_BLOCK_SIZE / 4,
        3 * HANDLE_BLOCK_SIZE,
        3 * HANDLE_BLOCK_SIZE + HANDLE_BLOCK_SIZE / 2,
        3 * HANDLE_BLOCK_SIZE + HANDLE_BLOCK_SIZE / 4,
    ];

    for size in sizes {
        let hm = HandleMemory::new();

        for _ in 0..size {
            hm.handle_address(1.into());
        }

        hm.push_border();

        for _ in 0..size {
            hm.handle_address(2.into());
        }

        hm.handle_address(2.into());

        hm.pop_border();

        assert_eq!(hm.iter().count(), size);
        assert!(hm.iter().all(|x| x.raw_load() == 1.into()));
    }
}

pub fn handle_scope<F: FnOnce() -> R, R>(f: F) -> R {
    let thread = current_thread();
    thread.handles.push_border();
    let result = f();
    thread.handles.pop_border();
    result
}
<|endoftext|>