<commit_before>extern crate sovrin;

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rust_base58;
#[macro_use]
extern crate serde_derive;
extern crate zmq;

use std::sync::mpsc::channel;
use std::thread;

use sovrin::api::ErrorCode;

#[macro_use]
#[path = "utils/mod.rs"]
mod utils;

use utils::agent::AgentUtils;
use utils::signus::SignusUtils;
use utils::test::TestUtils;
use utils::timeout::TimeoutUtils;
use utils::wallet::WalletUtils;

mod high_cases {
    use super::*;

    #[test]
    fn sovrin_agent_listen_works_with_sovrin_agent_connect() {
        TestUtils::cleanup_storage();
        let wallet_handle = WalletUtils::create_and_open_wallet("pool3", "wallet3", "default").unwrap();
        let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
        let endpoint = "tcp://127.0.0.1:9701";

        AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

        SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

        AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

        TestUtils::cleanup_storage();
    }

    mod sovrin_agent_connect {
        use super::*;
        use rust_base58::FromBase58;

        #[test]
        fn sovrin_agent_connect_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default").expect("create wallet");

            let seed: Option<String> = Some("sovrin_agent_connect_works_for_a".to_string());
            let (did, ver_key, pub_key) = SignusUtils::create_and_store_my_did(wallet_handle, seed).unwrap();
            let endpoint = "tcp://127.0.0.1:9702";

            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            //FIXME temporary code: replace by sovrin_agent_listen
            thread::spawn(move || {
                let secret_key = zmq::z85_encode("6wBM7yEYWD7wGd3ZtNQX5r31uWuC8NoZS2Lr6HZvRTY4".from_base58().unwrap().as_slice()).unwrap();
                let public_key = zmq::z85_encode("2vTqP9QfNdvPr397QaFKtbVUPbhgqmAum2oDVkYsk4p9".from_base58().unwrap().as_slice()).unwrap();
                let socket: zmq::Socket = zmq::Context::new().socket(zmq::SocketType::ROUTER).unwrap();
                socket.set_curve_publickey(public_key.as_str()).unwrap();
                socket.set_curve_secretkey(secret_key.as_str()).unwrap();
                socket.set_curve_server(true).unwrap();
                socket.bind(endpoint).unwrap();
                socket.poll(zmq::POLLIN, -1).unwrap();
                let identity = socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                let msg = socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                info!("Fake agent socket - recv - from {}, msg {}", identity, msg);
                if msg.eq("DID") {
                    info!("Fake agent socket send ACK");
                    socket.send_multipart(&[identity.as_bytes(), "DID_ACK".as_bytes()], zmq::DONTWAIT).unwrap();
                }
            });
            //FIXME /temporary code

            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_listen {
        use super::*;

        #[test]
        fn sovrin_agent_listen_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("pool2", "wallet2", "default").expect("create wallet");

            let seed: Option<String> = Some("sovrin_agent_listen_works_for_al".to_string());
            let (did, ver_key, pub_key) = SignusUtils::create_and_store_my_did(wallet_handle, seed).unwrap();
            let endpoint = "tcp://127.0.0.1:9703";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_send {
        use super::*;

        #[test]
        fn sovrin_agent_send_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let (wait_msg_from_srv_send, wait_msg_from_srv_recv) = channel();
            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool4", "wallet4", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9704";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            AgentUtils::listen(wallet_handle, endpoint,
                               Some(Box::new(move |_, conn_handle| {
                                   wait_conn_send.send(conn_handle).unwrap();
                               })),
                               Some(Box::new(move |_, msg| {
                                   wait_msg_from_cli_send.send(msg).unwrap();
                               }))).unwrap();
            let cli_to_srv_connect_id = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(),
                                                            Some(Box::new(move |_, msg| {
                                                                wait_msg_from_srv_send.send(msg).unwrap();
                                                            }))).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
            let client_msg = "msg_from_client";
            let server_msg = "msg_from_server";

            AgentUtils::send(cli_to_srv_connect_id, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);
            AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap();
            assert_eq!(wait_msg_from_srv_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), server_msg);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_connection {
        use super::*;

        #[test]
        fn sovrin_agent_close_connection_works_for_outgoing() {
            TestUtils::cleanup_storage();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool3", "wallet3", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9705";

            let _ = AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            AgentUtils::close_connection(conn_handle).unwrap();
            assert_eq!(AgentUtils::send(conn_handle, "").unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_agent_close_connection_works_for_incoming_conn() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool4", "wallet4", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9706";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            AgentUtils::listen(wallet_handle, endpoint,
                               Some(Box::new(move |_, conn_handle| {
                                   wait_conn_send.send(conn_handle).unwrap();
                               })),
                               None).unwrap();
            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

            AgentUtils::close_connection(srv_to_cli_connect_id).unwrap();

            let server_msg = "msg_from_server";
            assert_eq!(AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_listener {
        use super::*;

        #[test]
        fn sovrin_agent_close_listener_works() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool8", "wallet8", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9708";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let listener_handle = AgentUtils::listen(wallet_handle, endpoint,
                                                     Some(Box::new(move |_, conn_handle| {
                                                         wait_conn_send.send(conn_handle).unwrap();
                                                     })),
                                                     None).unwrap();
            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

            AgentUtils::close_listener(listener_handle).unwrap();

            let server_msg = "msg_from_server";
            assert_eq!(AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }
}

mod medium_cases {
    use super::*;

    mod sovrin_agent_close_connection {
        use super::*;

        #[test]
        fn sovrin_agent_close_connection_works_for_incorrect_conn_handle() {
            TestUtils::cleanup_storage();

            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool6", "wallet6", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9707";
            let _ = AgentUtils::listen(wallet_handle, endpoint, None,
                                       Some(Box::new(move |_, msg| {
                                           wait_msg_from_cli_send.send(msg).unwrap();
                                       }))).unwrap();
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            assert_eq!(AgentUtils::close_connection(conn_handle + 100).unwrap_err(), ErrorCode::CommonInvalidStructure);

            let client_msg = "msg_from_cli_to_srv";
            AgentUtils::send(conn_handle, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_listener {
        use super::*;

        #[test]
        fn sovrin_agent_close_listener_works_for_incorrect_handle() {
            TestUtils::cleanup_storage();

            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool9", "wallet9", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9709";
            let listener_handle = AgentUtils::listen(wallet_handle, endpoint, None,
                                                     Some(Box::new(move |_, msg| {
                                                         wait_msg_from_cli_send.send(msg).unwrap();
                                                     }))).unwrap();
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            let incorrect_listener_handle = conn_handle;
            assert_eq!(AgentUtils::close_listener(incorrect_listener_handle).unwrap_err(), ErrorCode::CommonInvalidStructure);

            let client_msg = "msg_from_cli_to_srv";
            AgentUtils::send(conn_handle, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);

            TestUtils::cleanup_storage();
        }
    }
}
<commit_msg>Fix compl warn in agent integration test.<commit_after>extern crate sovrin;

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rust_base58;
#[macro_use]
extern crate serde_derive;
extern crate zmq;

use std::sync::mpsc::channel;
use std::thread;

use sovrin::api::ErrorCode;

#[macro_use]
#[path = "utils/mod.rs"]
mod utils;

use utils::agent::AgentUtils;
use utils::signus::SignusUtils;
use utils::test::TestUtils;
use utils::timeout::TimeoutUtils;
use utils::wallet::WalletUtils;

mod high_cases {
    use super::*;

    #[test]
    fn sovrin_agent_listen_works_with_sovrin_agent_connect() {
        TestUtils::cleanup_storage();
        let wallet_handle = WalletUtils::create_and_open_wallet("pool3", "wallet3", "default").unwrap();
        let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
        let endpoint = "tcp://127.0.0.1:9701";

        AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

        SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

        AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

        TestUtils::cleanup_storage();
    }

    mod sovrin_agent_connect {
        use super::*;
        use rust_base58::FromBase58;

        #[test]
        fn sovrin_agent_connect_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("pool1", "wallet1", "default").expect("create wallet");

            let seed: Option<String> = Some("sovrin_agent_connect_works_for_a".to_string());
            let (did, ver_key, pub_key) = SignusUtils::create_and_store_my_did(wallet_handle, seed).unwrap();
            let endpoint = "tcp://127.0.0.1:9702";

            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            //FIXME temporary code: replace by sovrin_agent_listen
            thread::spawn(move || {
                let secret_key = zmq::z85_encode("6wBM7yEYWD7wGd3ZtNQX5r31uWuC8NoZS2Lr6HZvRTY4".from_base58().unwrap().as_slice()).unwrap();
                let public_key = zmq::z85_encode("2vTqP9QfNdvPr397QaFKtbVUPbhgqmAum2oDVkYsk4p9".from_base58().unwrap().as_slice()).unwrap();
                let socket: zmq::Socket = zmq::Context::new().socket(zmq::SocketType::ROUTER).unwrap();
                socket.set_curve_publickey(public_key.as_str()).unwrap();
                socket.set_curve_secretkey(secret_key.as_str()).unwrap();
                socket.set_curve_server(true).unwrap();
                socket.bind(endpoint).unwrap();
                socket.poll(zmq::POLLIN, -1).unwrap();
                let identity = socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                let msg = socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                info!("Fake agent socket - recv - from {}, msg {}", identity, msg);
                if msg.eq("DID") {
                    info!("Fake agent socket send ACK");
                    socket.send_multipart(&[identity.as_bytes(), "DID_ACK".as_bytes()], zmq::DONTWAIT).unwrap();
                }
            });
            //FIXME /temporary code

            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_listen {
        use super::*;

        #[test]
        fn sovrin_agent_listen_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let wallet_handle = WalletUtils::create_and_open_wallet("pool2", "wallet2", "default").expect("create wallet");

            let seed: Option<String> = Some("sovrin_agent_listen_works_for_al".to_string());
            let (did, ver_key, pub_key) = SignusUtils::create_and_store_my_did(wallet_handle, seed).unwrap();
            let endpoint = "tcp://127.0.0.1:9703";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_send {
        use super::*;

        #[test]
        fn sovrin_agent_send_works_for_all_data_in_wallet_present() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let (wait_msg_from_srv_send, wait_msg_from_srv_recv) = channel();
            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool4", "wallet4", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9704";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            AgentUtils::listen(wallet_handle, endpoint,
                               Some(Box::new(move |_, conn_handle| {
                                   wait_conn_send.send(conn_handle).unwrap();
                               })),
                               Some(Box::new(move |_, msg| {
                                   wait_msg_from_cli_send.send(msg).unwrap();
                               }))).unwrap();
            let cli_to_srv_connect_id = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(),
                                                            Some(Box::new(move |_, msg| {
                                                                wait_msg_from_srv_send.send(msg).unwrap();
                                                            }))).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
            let client_msg = "msg_from_client";
            let server_msg = "msg_from_server";

            AgentUtils::send(cli_to_srv_connect_id, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);
            AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap();
            assert_eq!(wait_msg_from_srv_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), server_msg);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_connection {
        use super::*;

        #[test]
        fn sovrin_agent_close_connection_works_for_outgoing() {
            TestUtils::cleanup_storage();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool3", "wallet3", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9705";

            let _ = AgentUtils::listen(wallet_handle, endpoint, None, None).unwrap();

            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();

            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            AgentUtils::close_connection(conn_handle).unwrap();
            assert_eq!(AgentUtils::send(conn_handle, "").unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }

        #[test]
        fn sovrin_agent_close_connection_works_for_incoming_conn() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool4", "wallet4", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9706";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            AgentUtils::listen(wallet_handle, endpoint,
                               Some(Box::new(move |_, conn_handle| {
                                   wait_conn_send.send(conn_handle).unwrap();
                               })),
                               None).unwrap();
            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

            AgentUtils::close_connection(srv_to_cli_connect_id).unwrap();

            let server_msg = "msg_from_server";
            assert_eq!(AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_listener {
        use super::*;

        #[test]
        fn sovrin_agent_close_listener_works() {
            TestUtils::cleanup_storage();

            let (wait_conn_send, wait_conn_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool8", "wallet8", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9708";
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let listener_handle = AgentUtils::listen(wallet_handle, endpoint,
                                                     Some(Box::new(move |_, conn_handle| {
                                                         wait_conn_send.send(conn_handle).unwrap();
                                                     })),
                                                     None).unwrap();
            AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();
            let srv_to_cli_connect_id = wait_conn_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap();

            AgentUtils::close_listener(listener_handle).unwrap();

            let server_msg = "msg_from_server";
            assert_eq!(AgentUtils::send(srv_to_cli_connect_id, server_msg).unwrap_err(), ErrorCode::CommonInvalidStructure);

            TestUtils::cleanup_storage();
        }
    }
}

mod medium_cases {
    use super::*;

    mod sovrin_agent_close_connection {
        use super::*;

        #[test]
        fn sovrin_agent_close_connection_works_for_incorrect_conn_handle() {
            TestUtils::cleanup_storage();

            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool6", "wallet6", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9707";
            let _ = AgentUtils::listen(wallet_handle, endpoint, None,
                                       Some(Box::new(move |_, msg| {
                                           wait_msg_from_cli_send.send(msg).unwrap();
                                       }))).unwrap();
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            assert_eq!(AgentUtils::close_connection(conn_handle + 100).unwrap_err(), ErrorCode::CommonInvalidStructure);

            let client_msg = "msg_from_cli_to_srv";
            AgentUtils::send(conn_handle, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);

            TestUtils::cleanup_storage();
        }
    }

    mod sovrin_agent_close_listener {
        use super::*;

        #[test]
        fn sovrin_agent_close_listener_works_for_incorrect_handle() {
            TestUtils::cleanup_storage();

            let (wait_msg_from_cli_send, wait_msg_from_cli_recv) = channel();
            let wallet_handle = WalletUtils::create_and_open_wallet("pool9", "wallet9", "default").unwrap();
            let (did, ver_key, pub_key): (String, String, String) = SignusUtils::create_and_store_my_did(wallet_handle, None).unwrap();
            let endpoint = "tcp://127.0.0.1:9709";
            AgentUtils::listen(wallet_handle, endpoint, None,
                                                     Some(Box::new(move |_, msg| {
                                                         wait_msg_from_cli_send.send(msg).unwrap();
                                                     }))).unwrap();
            SignusUtils::store_their_did_from_parts(wallet_handle, did.as_str(), pub_key.as_str(), ver_key.as_str(), endpoint).unwrap();
            let conn_handle = AgentUtils::connect(wallet_handle, did.as_str(), did.as_str(), None).unwrap();

            let incorrect_listener_handle = conn_handle;
            assert_eq!(AgentUtils::close_listener(incorrect_listener_handle).unwrap_err(), ErrorCode::CommonInvalidStructure);

            let client_msg = "msg_from_cli_to_srv";
            AgentUtils::send(conn_handle, client_msg).unwrap();
            assert_eq!(wait_msg_from_cli_recv.recv_timeout(TimeoutUtils::short_timeout()).unwrap(), client_msg);

            TestUtils::cleanup_storage();
        }
    }
}
<|endoftext|>


<commit_before>//! Contains utilities for generating suggestions for borrowck errors related to unsatisified
//! outlives constraints.

use std::collections::BTreeMap;

use log::debug;
use rustc::{hir::def_id::DefId, infer::InferCtxt, mir::Body, ty::RegionVid};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Diagnostic, DiagnosticBuilder};

use smallvec::SmallVec;

use crate::borrow_check::nll::region_infer::{
    error_reporting::{
        region_name::{RegionName, RegionNameSource},
        ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
    },
    RegionInferenceContext,
};

/// The different things we could suggest.
enum SuggestedConstraint {
    /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ...
    Outlives(RegionName, SmallVec<[RegionName; 2]>),

    /// 'a = 'b
    Equal(RegionName, RegionName),

    /// 'a: 'static i.e. 'a = 'static and the user should just use 'static
    Static(RegionName),
}

/// Collects information about outlives constraints that needed to be added for a given MIR node
/// corresponding to a function definition.
///
/// Adds a help note suggesting adding a where clause with the needed constraints.
pub struct OutlivesSuggestionBuilder {
    /// The MIR DefId of the fn with the lifetime error.
    mir_def_id: DefId,

    /// The list of outlives constraints that need to be added. Specifically, we map each free
    /// region to all other regions that it must outlive. I will use the shorthand `fr:
    /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
    /// implicit free regions that we inferred. These will need to be given names in the final
    /// suggestion message.
    constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
}

impl OutlivesSuggestionBuilder {
    /// Create a new builder for the given MIR node representing a fn definition.
    crate fn new(mir_def_id: DefId) -> Self {
        OutlivesSuggestionBuilder { mir_def_id, constraints_to_add: BTreeMap::default() }
    }

    /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
    /// suggestion.
    //
    // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound
    // region or a named region, avoiding using regions with synthetic names altogether. This
    // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args).
    // We can probably be less conservative, since some inferred free regions are namable (e.g.
    // the user can explicitly name them. To do this, we would allow some regions whose names
    // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as
    // naming the `'self` lifetime in methods, etc.
    fn region_name_is_suggestable(name: &RegionName) -> bool {
        match name.source {
            RegionNameSource::NamedEarlyBoundRegion(..)
            | RegionNameSource::NamedFreeRegion(..)
            | RegionNameSource::Static => {
                debug!("Region {:?} is suggestable", name);
                true
            }

            // Don't give suggestions for upvars, closure return types, or other unnamable
            // regions.
            RegionNameSource::SynthesizedFreeEnvRegion(..)
            | RegionNameSource::CannotMatchHirTy(..)
            | RegionNameSource::MatchedHirTy(..)
            | RegionNameSource::MatchedAdtAndSegment(..)
            | RegionNameSource::AnonRegionFromUpvar(..)
            | RegionNameSource::AnonRegionFromOutput(..)
            | RegionNameSource::AnonRegionFromYieldTy(..) => {
                debug!("Region {:?} is NOT suggestable", name);
                false
            }
        }
    }

    /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`.
    fn region_vid_to_name(
        &self,
        errctx: &ErrorReportingCtx<'_, '_, '_>,
        renctx: &mut RegionErrorNamingCtx,
        region: RegionVid,
    ) -> Option<RegionName> {
        errctx
            .region_infcx
            .give_region_a_name(errctx, renctx, region)
            .filter(Self::region_name_is_suggestable)
    }

    /// Compiles a list of all suggestions to be printed in the final big suggestion.
    fn compile_all_suggestions<'tcx>(
        &self,
        body: &Body<'tcx>,
        region_infcx: &RegionInferenceContext<'tcx>,
        infcx: &InferCtxt<'_, 'tcx>,
        renctx: &mut RegionErrorNamingCtx,
    ) -> SmallVec<[SuggestedConstraint; 2]> {
        let mut suggested = SmallVec::new();

        // Keep track of variables that we have already suggested unifying so that we don't print
        // out silly duplicate messages.
        let mut unified_already = FxHashSet::default();

        let errctx = ErrorReportingCtx {
            region_infcx,
            infcx,
            body,
            mir_def_id: self.mir_def_id,

            // We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
            // should never be used.
            upvars: &[],
        };

        for (fr, outlived) in &self.constraints_to_add {
            let fr_name = if let Some(fr_name) = self.region_vid_to_name(&errctx, renctx, *fr) {
                fr_name
            } else {
                continue;
            };

            let outlived = outlived
                .iter()
                // if there is a `None`, we will just omit that constraint
                .filter_map(|fr| {
                    self.region_vid_to_name(&errctx, renctx, *fr).map(|rname| (fr, rname))
                })
                .collect::<Vec<_>>();

            // No suggestable outlived lifetimes.
            if outlived.is_empty() {
                continue;
            }

            // There are three types of suggestions we can make:
            // 1) Suggest a bound: 'a: 'b
            // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we
            //    should just replace 'a with 'static.
            // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a

            if outlived.iter().any(|(_, outlived_name)| {
                if let RegionNameSource::Static = outlived_name.source {
                    true
                } else {
                    false
                }
            }) {
                suggested.push(SuggestedConstraint::Static(fr_name));
            } else {
                // We want to isolate out all lifetimes that should be unified and print out
                // separate messages for them.

                let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition(
                    // Do we have both 'fr: 'r and 'r: 'fr?
                    |(r, _)| {
                        self.constraints_to_add
                            .get(r)
                            .map(|r_outlived| r_outlived.as_slice().contains(fr))
                            .unwrap_or(false)
                    },
                );

                for (r, bound) in unified.into_iter() {
                    if !unified_already.contains(fr) {
                        suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound));
                        unified_already.insert(r);
                    }
                }

                if !other.is_empty() {
                    let other =
                        other.iter().map(|(_, rname)| rname.clone()).collect::<SmallVec<_>>();
                    suggested.push(SuggestedConstraint::Outlives(fr_name, other))
                }
            }
        }

        suggested
    }

    /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest.
    crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
        debug!("Collected {:?}: {:?}", fr, outlived_fr);

        // Add to set of constraints for final help note.
        self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
    }

    /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
    /// suggestable.
    crate fn intermediate_suggestion(
        &mut self,
        errctx: &ErrorReportingCtx<'_, '_, '_>,
        errci: &ErrorConstraintInfo,
        renctx: &mut RegionErrorNamingCtx,
        diag: &mut DiagnosticBuilder<'_>,
    ) {
        // Emit an intermediate note.
        let fr_name = self.region_vid_to_name(errctx, renctx, errci.fr);
        let outlived_fr_name = self.region_vid_to_name(errctx, renctx, errci.outlived_fr);

        if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
            if let RegionNameSource::Static = outlived_fr_name.source {
                diag.help(&format!("consider replacing `{}` with `'static`", fr_name));
            } else {
                diag.help(&format!(
                    "consider adding the following bound: `{}: {}`",
                    fr_name, outlived_fr_name
                ));
            }
        }
    }

    /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final
    /// suggestion including all collected constraints.
    crate fn add_suggestion<'tcx>(
        &self,
        body: &Body<'tcx>,
        region_infcx: &RegionInferenceContext<'tcx>,
        infcx: &InferCtxt<'_, 'tcx>,
        errors_buffer: &mut Vec<Diagnostic>,
        renctx: &mut RegionErrorNamingCtx,
    ) {
        // No constraints to add? Done.
        if self.constraints_to_add.is_empty() {
            debug!("No constraints to suggest.");
            return;
        }

        // If there is only one constraint to suggest, then we already suggested it in the
        // intermediate suggestion above.
        if self.constraints_to_add.len() == 1 {
            debug!("Only 1 suggestion. Skipping.");
            return;
        }

        // Get all suggestable constraints.
        let suggested = self.compile_all_suggestions(body, region_infcx, infcx, renctx);

        // If there are no suggestable constraints...
        if suggested.is_empty() {
            debug!("Only 1 suggestable constraint. Skipping.");
            return;
        }

        // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
        // list of diagnostics.
        let mut diag = if suggested.len() == 1 {
            infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
                SuggestedConstraint::Outlives(a, bs) => {
                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
                    format!("add bound `{}: {}`", a, bs.join(" + "))
                }

                SuggestedConstraint::Equal(a, b) => {
                    format!("`{}` and `{}` must be the same: replace one with the other", a, b)
                }
                SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
            })
        } else {
            // Create a new diagnostic.
            let mut diag = infcx
                .tcx
                .sess
                .diagnostic()
                .struct_help("the following changes may resolve your lifetime errors");

            // Add suggestions.
            for constraint in suggested {
                match constraint {
                    SuggestedConstraint::Outlives(a, bs) => {
                        let bs: SmallVec<[String; 2]> =
                            bs.iter().map(|r| format!("{}", r)).collect();
                        diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
                    }
                    SuggestedConstraint::Equal(a, b) => {
                        diag.help(&format!(
                            "`{}` and `{}` must be the same: replace one with the other",
                            a, b
                        ));
                    }
                    SuggestedConstraint::Static(a) => {
                        diag.help(&format!("replace `{}` with `'static`", a));
                    }
                }
            }

            diag
        };

        // We want this message to appear after other messages on the mir def.
        let mir_span = infcx.tcx.def_span(self.mir_def_id);
        diag.sort_span = mir_span.shrink_to_hi();

        // Buffer the diagnostic
        diag.buffer(errors_buffer);
    }
}
<commit_msg>hack around '_ named regions<commit_after>//! Contains utilities for generating suggestions for borrowck errors related to unsatisified
//! outlives constraints.

use std::collections::BTreeMap;

use log::debug;
use rustc::{hir::def_id::DefId, infer::InferCtxt, mir::Body, ty::RegionVid};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Diagnostic, DiagnosticBuilder};

use smallvec::SmallVec;

use crate::borrow_check::nll::region_infer::{
    error_reporting::{
        region_name::{RegionName, RegionNameSource},
        ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
    },
    RegionInferenceContext,
};

/// The different things we could suggest.
enum SuggestedConstraint {
    /// Outlives(a, [b, c, d, ...]) => 'a: 'b + 'c + 'd + ...
    Outlives(RegionName, SmallVec<[RegionName; 2]>),

    /// 'a = 'b
    Equal(RegionName, RegionName),

    /// 'a: 'static i.e. 'a = 'static and the user should just use 'static
    Static(RegionName),
}

/// Collects information about outlives constraints that needed to be added for a given MIR node
/// corresponding to a function definition.
///
/// Adds a help note suggesting adding a where clause with the needed constraints.
pub struct OutlivesSuggestionBuilder {
    /// The MIR DefId of the fn with the lifetime error.
    mir_def_id: DefId,

    /// The list of outlives constraints that need to be added. Specifically, we map each free
    /// region to all other regions that it must outlive. I will use the shorthand `fr:
    /// outlived_frs`. Not all of these regions will already have names necessarily. Some could be
    /// implicit free regions that we inferred. These will need to be given names in the final
    /// suggestion message.
    constraints_to_add: BTreeMap<RegionVid, Vec<RegionVid>>,
}

impl OutlivesSuggestionBuilder {
    /// Create a new builder for the given MIR node representing a fn definition.
    crate fn new(mir_def_id: DefId) -> Self {
        OutlivesSuggestionBuilder { mir_def_id, constraints_to_add: BTreeMap::default() }
    }

    /// Returns `true` iff the `RegionNameSource` is a valid source for an outlives
    /// suggestion.
    //
    // FIXME: Currently, we only report suggestions if the `RegionNameSource` is an early-bound
    // region or a named region, avoiding using regions with synthetic names altogether. This
    // allows us to avoid giving impossible suggestions (e.g. adding bounds to closure args).
    // We can probably be less conservative, since some inferred free regions are namable (e.g.
    // the user can explicitly name them. To do this, we would allow some regions whose names
    // come from `MatchedAdtAndSegment`, being careful to filter out bad suggestions, such as
    // naming the `'self` lifetime in methods, etc.
    fn region_name_is_suggestable(name: &RegionName) -> bool {
        match name.source {
            RegionNameSource::NamedEarlyBoundRegion(..)
            | RegionNameSource::NamedFreeRegion(..)
            | RegionNameSource::Static => {
                // FIXME: This is a bit hacky. We should ideally have a semantic way for checking
                // if the name is `'_`...
                if name.name().with(|name| name != "'_") {
                    debug!("Region {:?} is suggestable", name);
                    true
                } else {
                    debug!("Region {:?} is NOT suggestable", name);
                    false
                }
            }

            // Don't give suggestions for upvars, closure return types, or other unnamable
            // regions.
            RegionNameSource::SynthesizedFreeEnvRegion(..)
            | RegionNameSource::CannotMatchHirTy(..)
            | RegionNameSource::MatchedHirTy(..)
            | RegionNameSource::MatchedAdtAndSegment(..)
            | RegionNameSource::AnonRegionFromUpvar(..)
            | RegionNameSource::AnonRegionFromOutput(..)
            | RegionNameSource::AnonRegionFromYieldTy(..) => {
                debug!("Region {:?} is NOT suggestable", name);
                false
            }
        }
    }

    /// Returns a name for the region if it is suggestable. See `region_name_is_suggestable`.
    fn region_vid_to_name(
        &self,
        errctx: &ErrorReportingCtx<'_, '_, '_>,
        renctx: &mut RegionErrorNamingCtx,
        region: RegionVid,
    ) -> Option<RegionName> {
        errctx
            .region_infcx
            .give_region_a_name(errctx, renctx, region)
            .filter(Self::region_name_is_suggestable)
    }

    /// Compiles a list of all suggestions to be printed in the final big suggestion.
    fn compile_all_suggestions<'tcx>(
        &self,
        body: &Body<'tcx>,
        region_infcx: &RegionInferenceContext<'tcx>,
        infcx: &InferCtxt<'_, 'tcx>,
        renctx: &mut RegionErrorNamingCtx,
    ) -> SmallVec<[SuggestedConstraint; 2]> {
        let mut suggested = SmallVec::new();

        // Keep track of variables that we have already suggested unifying so that we don't print
        // out silly duplicate messages.
        let mut unified_already = FxHashSet::default();

        let errctx = ErrorReportingCtx {
            region_infcx,
            infcx,
            body,
            mir_def_id: self.mir_def_id,

            // We should not be suggesting naming upvars, so we pass in a dummy set of upvars that
            // should never be used.
            upvars: &[],
        };

        for (fr, outlived) in &self.constraints_to_add {
            let fr_name = if let Some(fr_name) = self.region_vid_to_name(&errctx, renctx, *fr) {
                fr_name
            } else {
                continue;
            };

            let outlived = outlived
                .iter()
                // if there is a `None`, we will just omit that constraint
                .filter_map(|fr| {
                    self.region_vid_to_name(&errctx, renctx, *fr).map(|rname| (fr, rname))
                })
                .collect::<Vec<_>>();

            // No suggestable outlived lifetimes.
            if outlived.is_empty() {
                continue;
            }

            // There are three types of suggestions we can make:
            // 1) Suggest a bound: 'a: 'b
            // 2) Suggest replacing 'a with 'static. If any of `outlived` is `'static`, then we
            //    should just replace 'a with 'static.
            // 3) Suggest unifying 'a with 'b if we have both 'a: 'b and 'b: 'a

            if outlived.iter().any(|(_, outlived_name)| {
                if let RegionNameSource::Static = outlived_name.source {
                    true
                } else {
                    false
                }
            }) {
                suggested.push(SuggestedConstraint::Static(fr_name));
            } else {
                // We want to isolate out all lifetimes that should be unified and print out
                // separate messages for them.

                let (unified, other): (Vec<_>, Vec<_>) = outlived.into_iter().partition(
                    // Do we have both 'fr: 'r and 'r: 'fr?
                    |(r, _)| {
                        self.constraints_to_add
                            .get(r)
                            .map(|r_outlived| r_outlived.as_slice().contains(fr))
                            .unwrap_or(false)
                    },
                );

                for (r, bound) in unified.into_iter() {
                    if !unified_already.contains(fr) {
                        suggested.push(SuggestedConstraint::Equal(fr_name.clone(), bound));
                        unified_already.insert(r);
                    }
                }

                if !other.is_empty() {
                    let other =
                        other.iter().map(|(_, rname)| rname.clone()).collect::<SmallVec<_>>();
                    suggested.push(SuggestedConstraint::Outlives(fr_name, other))
                }
            }
        }

        suggested
    }

    /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest.
    crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
        debug!("Collected {:?}: {:?}", fr, outlived_fr);

        // Add to set of constraints for final help note.
        self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr);
    }

    /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
    /// suggestable.
    crate fn intermediate_suggestion(
        &mut self,
        errctx: &ErrorReportingCtx<'_, '_, '_>,
        errci: &ErrorConstraintInfo,
        renctx: &mut RegionErrorNamingCtx,
        diag: &mut DiagnosticBuilder<'_>,
    ) {
        // Emit an intermediate note.
        let fr_name = self.region_vid_to_name(errctx, renctx, errci.fr);
        let outlived_fr_name = self.region_vid_to_name(errctx, renctx, errci.outlived_fr);

        if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
            if let RegionNameSource::Static = outlived_fr_name.source {
                diag.help(&format!("consider replacing `{}` with `'static`", fr_name));
            } else {
                diag.help(&format!(
                    "consider adding the following bound: `{}: {}`",
                    fr_name, outlived_fr_name
                ));
            }
        }
    }

    /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final
    /// suggestion including all collected constraints.
    crate fn add_suggestion<'tcx>(
        &self,
        body: &Body<'tcx>,
        region_infcx: &RegionInferenceContext<'tcx>,
        infcx: &InferCtxt<'_, 'tcx>,
        errors_buffer: &mut Vec<Diagnostic>,
        renctx: &mut RegionErrorNamingCtx,
    ) {
        // No constraints to add? Done.
        if self.constraints_to_add.is_empty() {
            debug!("No constraints to suggest.");
            return;
        }

        // If there is only one constraint to suggest, then we already suggested it in the
        // intermediate suggestion above.
        if self.constraints_to_add.len() == 1 {
            debug!("Only 1 suggestion. Skipping.");
            return;
        }

        // Get all suggestable constraints.
        let suggested = self.compile_all_suggestions(body, region_infcx, infcx, renctx);

        // If there are no suggestable constraints...
        if suggested.is_empty() {
            debug!("Only 1 suggestable constraint. Skipping.");
            return;
        }

        // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
        // list of diagnostics.
        let mut diag = if suggested.len() == 1 {
            infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
                SuggestedConstraint::Outlives(a, bs) => {
                    let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect();
                    format!("add bound `{}: {}`", a, bs.join(" + "))
                }

                SuggestedConstraint::Equal(a, b) => {
                    format!("`{}` and `{}` must be the same: replace one with the other", a, b)
                }
                SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a),
            })
        } else {
            // Create a new diagnostic.
            let mut diag = infcx
                .tcx
                .sess
                .diagnostic()
                .struct_help("the following changes may resolve your lifetime errors");

            // Add suggestions.
            for constraint in suggested {
                match constraint {
                    SuggestedConstraint::Outlives(a, bs) => {
                        let bs: SmallVec<[String; 2]> =
                            bs.iter().map(|r| format!("{}", r)).collect();
                        diag.help(&format!("add bound `{}: {}`", a, bs.join(" + ")));
                    }
                    SuggestedConstraint::Equal(a, b) => {
                        diag.help(&format!(
                            "`{}` and `{}` must be the same: replace one with the other",
                            a, b
                        ));
                    }
                    SuggestedConstraint::Static(a) => {
                        diag.help(&format!("replace `{}` with `'static`", a));
                    }
                }
            }

            diag
        };

        // We want this message to appear after other messages on the mir def.
        let mir_span = infcx.tcx.def_span(self.mir_def_id);
        diag.sort_span = mir_span.shrink_to_hi();

        // Buffer the diagnostic
        diag.buffer(errors_buffer);
    }
}
<|endoftext|>


<commit_before>use super::super::{ Network, NodeId };

/// Runs pagerank algorithm on a graph until convergence.
/// Convergence is reached, when the last ranks vector and the new one
/// differ by less than `eps` in their L1-norm.
/// `beta` is the teleport probability. CAUTION: Never use a teleport
/// probability of `beta == 0.0`!!! Due to precision errors in the double
/// values, the sum of the ranks vector elements can exceed `1.0` which
/// will be caught by an assertion and the algorithm will panic.
/// The result will be the pagerank for each node in the network.
pub fn pagerank<N: Network>(network: &N, beta: f64, eps: f64) -> Vec<f64> {
  let init_value = 1.0 / (network.num_nodes() as f64);
  let mut ranks = vec![0.0; network.num_nodes()];
  let mut new_ranks = vec![init_value; network.num_nodes()];
  let adj_lists = build_adj_list(network);
  let inv_out_deg = inv_out_deg(network);
  let mut i = 0;
  while !is_converged(&ranks, &new_ranks, eps) {
    print!("iteration {}: ", i);
    ranks = new_ranks;
    new_ranks = mult_matrix_vec(&adj_lists, &inv_out_deg, beta, &ranks);
    normalize(&mut new_ranks);
    i+=1;
  }
  ranks
}
/// Calculates the inverse of the out degree for each node in the network.
/// For out degree `0`, the inverse will also be `0`, guaranteeing that we
/// add `0.0` to the pagerank of the respective node.
fn inv_out_deg<N: Network>(network: &N) -> Vec<f64> {
  let mut inv_out_deg = Vec::with_capacity(network.num_nodes());
  for i in 0..network.num_nodes() {
    let out_deg = network.adjacent(i as NodeId).len() as f64;
    if out_deg > 0.0 {
      inv_out_deg.push(1.0 / out_deg);
    } else {
      inv_out_deg.push(0.0);
    }
  }
  inv_out_deg
}

/// Converts the network in a slightly faster traversable adjacency list.
fn build_adj_list<N: Network>(network: &N) -> Vec<Vec<usize>> {
  let mut adj_list = Vec::with_capacity(network.num_nodes());
  for i in 0..network.num_nodes() {
    let adj_nodes = network.adjacent(i as NodeId);
    let mut i_th_adj_nodes = Vec::with_capacity(adj_nodes.len());
    for j in adj_nodes {
      i_th_adj_nodes.push(j as usize);
    }
    adj_list.push(i_th_adj_nodes);
  }
  adj_list
}

/// Normalize the vector to \sum_i v_i = 1. Remaining mass is distributed
/// evenly over all nodes. (Also known as smoothing.)
/// # Panics
/// If the sum of all elements is greater than `1.0`
fn normalize(vector: &mut Vec<f64>) {
  let mut sum = 0.0;
  for i in 0..vector.len() {
    sum += vector[i];
  }

  assert!(sum <= 1.0);
  let corrective_value = (1.0 - sum)/(vector.len() as f64);
  for i in 0..vector.len() {
    vector[i] += corrective_value;
  }
}

/// Multiply the ranks vector with the adjacency matrix. Every entry is
/// damped by `1.0 - beta`. The vector is multiplied from the left!
fn mult_matrix_vec(adj_list: &Vec<Vec<usize>>, inv_out_degs: &Vec<f64>, beta: f64, current: &Vec<f64>) -> Vec<f64> {
  let mut new_ranks = vec![0.0; current.len()];
  for source_node in 0..current.len() {
    let inv_out_deg = inv_out_degs[source_node];
    for target_node in &adj_list[source_node] {
      new_ranks[*target_node] += (1.0-beta) * inv_out_deg * current[source_node];
    }
  }
  new_ranks
}

/// Determines convergence for two vectors with respect to the tolerance.
fn is_converged(old: &Vec<f64>, new: &Vec<f64>, eps: f64) -> bool {
  assert!(old.len() == new.len());
  let mut sum = 0.0;
  for i in 0..old.len() {
    sum += (old[i] - new[i]).abs();
  }
  println!("{:e} ({:e})", sum, eps);
  sum <= eps
}

#[test]
fn test_inv_out_deg() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  assert_eq!(vec![1.0/3.0, 1.0/2.0, 1.0/1.0, 1.0/2.0], inv_out_deg(&compact_star));
}

#[test]
fn test_build_adj_list() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  let adj_list = vec![vec![1,2,3], vec![2,3], vec![0], vec![0,2]];
  assert_eq!(adj_list, build_adj_list(&compact_star));
}

#[test]
fn test_normalize() {
  let mut to_normalize = vec![0.125, 0.125, 0.125, 0.125];
  normalize(&mut to_normalize);
  assert_eq!(vec![0.25, 0.25, 0.25, 0.25], to_normalize);
}

#[test]
fn test_is_converged() {
  let v1 = vec![0.0; 5];
  let v2 = vec![1.0; 5];
  let v3 = vec![1.0, 1.0, 1.0, 1.0, 1.00000001];
  assert!(is_converged(&v1, &v1, 1e-6));
  assert!(!is_converged(&v1, &v2, 1e-6));
  assert!(is_converged(&v2, &v3, 1e-4));
}

#[test]
fn test_pagerank() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  let ranks = pagerank(&compact_star, 1e-10,1e-3);
  assert_eq!(vec![0.38,0.12,0.29,0.19], ranks);
}
<commit_msg>for pagerank, changed to L2 norm for convrgence criteria<commit_after>use super::super::{ Network, NodeId };

/// Runs pagerank algorithm on a graph until convergence.
/// Convergence is reached, when the last ranks vector and the new one
/// differ by less than `eps` in their L1-norm.
/// `beta` is the teleport probability. CAUTION: Never use a teleport
/// probability of `beta == 0.0`!!! Due to precision errors in the double
/// values, the sum of the ranks vector elements can exceed `1.0` which
/// will be caught by an assertion and the algorithm will panic.
/// The result will be the pagerank for each node in the network.
pub fn pagerank<N: Network>(network: &N, beta: f64, eps: f64) -> Vec<f64> {
  let init_value = 1.0 / (network.num_nodes() as f64);
  let mut ranks = vec![0.0; network.num_nodes()];
  let mut new_ranks = vec![init_value; network.num_nodes()];
  let adj_lists = build_adj_list(network);
  let inv_out_deg = inv_out_deg(network);
  let mut i = 0;
  while !is_converged(&ranks, &new_ranks, eps) {
    print!("iteration {}: ", i);
    ranks = new_ranks;
    new_ranks = mult_matrix_vec(&adj_lists, &inv_out_deg, beta, &ranks);
    normalize(&mut new_ranks);
    i+=1;
  }
  ranks
}
/// Calculates the inverse of the out degree for each node in the network.
/// For out degree `0`, the inverse will also be `0`, guaranteeing that we
/// add `0.0` to the pagerank of the respective node.
fn inv_out_deg<N: Network>(network: &N) -> Vec<f64> {
  let mut inv_out_deg = Vec::with_capacity(network.num_nodes());
  for i in 0..network.num_nodes() {
    let out_deg = network.adjacent(i as NodeId).len() as f64;
    if out_deg > 0.0 {
      inv_out_deg.push(1.0 / out_deg);
    } else {
      inv_out_deg.push(0.0);
    }
  }
  inv_out_deg
}

/// Converts the network in a slightly faster traversable adjacency list.
fn build_adj_list<N: Network>(network: &N) -> Vec<Vec<usize>> {
  let mut adj_list = Vec::with_capacity(network.num_nodes());
  for i in 0..network.num_nodes() {
    let adj_nodes = network.adjacent(i as NodeId);
    let mut i_th_adj_nodes = Vec::with_capacity(adj_nodes.len());
    for j in adj_nodes {
      i_th_adj_nodes.push(j as usize);
    }
    adj_list.push(i_th_adj_nodes);
  }
  adj_list
}

/// Normalize the vector to \sum_i v_i = 1. Remaining mass is distributed
/// evenly over all nodes. (Also known as smoothing.)
/// # Panics
/// If the sum of all elements is greater than `1.0`
fn normalize(vector: &mut Vec<f64>) {
  let mut sum = 0.0;
  for i in 0..vector.len() {
    sum += vector[i];
  }

  assert!(sum <= 1.0);
  let corrective_value = (1.0 - sum)/(vector.len() as f64);
  for i in 0..vector.len() {
    vector[i] += corrective_value;
  }
}

/// Multiply the ranks vector with the adjacency matrix. Every entry is
/// damped by `1.0 - beta`. The vector is multiplied from the left!
fn mult_matrix_vec(adj_list: &Vec<Vec<usize>>, inv_out_degs: &Vec<f64>, beta: f64, current: &Vec<f64>) -> Vec<f64> {
  let mut new_ranks = vec![0.0; current.len()];
  for source_node in 0..current.len() {
    let inv_out_deg = inv_out_degs[source_node];
    for target_node in &adj_list[source_node] {
      new_ranks[*target_node] += (1.0-beta) * inv_out_deg * current[source_node];
    }
  }
  new_ranks
}

/// Determines convergence for two vectors with respect to the tolerance.
fn is_converged(old: &Vec<f64>, new: &Vec<f64>, eps: f64) -> bool {
  assert!(old.len() == new.len());
  let mut sum = 0.0;
  for i in 0..old.len() {
    sum += (old[i] - new[i]).powi(2);
  }
  println!("{:e} ({:e})", sum.sqrt(), eps);
  sum.sqrt() <= eps
}

#[test]
fn test_inv_out_deg() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  assert_eq!(vec![1.0/3.0, 1.0/2.0, 1.0/1.0, 1.0/2.0], inv_out_deg(&compact_star));
}

#[test]
fn test_build_adj_list() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  let adj_list = vec![vec![1,2,3], vec![2,3], vec![0], vec![0,2]];
  assert_eq!(adj_list, build_adj_list(&compact_star));
}

#[test]
fn test_normalize() {
  let mut to_normalize = vec![0.125, 0.125, 0.125, 0.125];
  normalize(&mut to_normalize);
  assert_eq!(vec![0.25, 0.25, 0.25, 0.25], to_normalize);
}

#[test]
fn test_is_converged() {
  let v1 = vec![0.0; 5];
  let v2 = vec![1.0; 5];
  let v3 = vec![1.0, 1.0, 1.0, 1.0, 1.00000001];
  assert!(is_converged(&v1, &v1, 1e-6));
  assert!(!is_converged(&v1, &v2, 1e-6));
  assert!(is_converged(&v2, &v3, 1e-4));
}

#[test]
fn test_pagerank() {
  use super::super::compact_star::compact_star_from_edge_vec;
  let mut edges = vec![
      (0,1,0.0,0.0),
      (0,2,0.0,0.0),
      (0,3,0.0,0.0),
      (1,2,0.0,0.0),
      (1,3,0.0,0.0),
      (2,0,0.0,0.0),
      (3,0,0.0,0.0),
      (3,2,0.0,0.0)];
  let compact_star = compact_star_from_edge_vec(4, &mut edges);
  let ranks = pagerank(&compact_star, 1e-10,1e-3);
  assert_eq!(vec![0.38,0.12,0.29,0.19], ranks);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
#[derive(Clone, Debug)]
pub struct Iter<T>(Range<T>);

impl<T> Iterator for Iter<T> where Range<T>: Iterator
{
    type Item = <Range<T> as Iterator>::Item;
    fn next(&mut self) -> Option<Self::Item> { self.0.next() }
    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low - 1 != xlow { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, stride: isize) -> bool {
    if stride == 0 {
        return true
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, stride: i8) -> bool {
    if stride == 0 {
        return true
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone() + &sb;
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

}
<commit_msg>Add tests for multipeek and step<commit_after>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
#[derive(Clone, Debug)]
pub struct Iter<T>(Range<T>);

impl<T> Iterator for Iter<T> where Range<T>: Iterator
{
    type Item = <Range<T> as Iterator>::Item;
    fn next(&mut self) -> Option<Self::Item> { self.0.next() }
    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low != xlow + 1 { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, mut stride: isize) -> bool {
    if stride == 0 {
        stride += 1; // never zero
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, mut stride: i8) -> bool {
    if stride == 0 {
        // never zero
        stride += 1;
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn size_step(a: Iter<u16>, mut s: usize) -> bool {
    if s == 0 {
        s += 1; // never zero
    }
    exact_size(a.step(s))
}

#[quickcheck]
fn size_multipeek(a: Iter<u16>, s: u8) -> bool {
    let mut it = a.multipeek();
    // peek a few times
    for _ in 0..s {
        it.peek();
    }
    exact_size(it)
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone() + &sb;
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

}
<|endoftext|>


<commit_before>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_api::Outgoing;
use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerKeyId, ServerName};
use serde::{Deserialize, Serialize};

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a str,

    /// The Matrix ID of the invitee.
    pub mxid: &'a str,

    /// The state key of the m.third_party_invite event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Invite3pid {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: String,

    /// An access token registered with the identity server.
    pub id_access_token: String,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: String,
}
<commit_msg>Replace last explicit use of Box<ServerName> outside ruma-identifiers<commit_after>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_api::Outgoing;
use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ServerKeyId, ServerNameBox};
use serde::{Deserialize, Serialize};

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a str,

    /// The Matrix ID of the invitee.
    pub mxid: &'a str,

    /// The state key of the m.third_party_invite event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Invite3pid {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: String,

    /// An access token registered with the identity server.
    pub id_access_token: String,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: String,
}
<|endoftext|>