<commit_before>#[macro_use] extern crate pact_matching;
extern crate rustc_serialize;
#[macro_use(expect)] extern crate expectest;
#[macro_use] extern crate p_macro;

mod spec_testcases;

use pact_matching::models::Pact;
use std::path::Path;
use expectest::prelude::*;
use rustc_serialize::json::Json;
use std::fs::File;

#[test]
fn test_load_pact() {
    let pact_file = Path::new(file!()).parent().unwrap().join("pact.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification")).to(be_none());
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_pact_encoded_query() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_encoded_query.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));

            let pact_interactions = pact_json.find("interactions").unwrap().as_array().unwrap();
            let pact_interactions_from_file = pact_json_from_file.find("interactions").unwrap().as_array().unwrap();
            expect(pact_interactions.len()).to(be_equal_to(pact_interactions_from_file.len()));

            for (pact_interaction, file_interaction) in pact_interactions.iter().zip(pact_interactions_from_file.iter()) {
                expect(pact_interaction.find("providerState")).to(be_equal_to(file_interaction.find("providerState")));
                expect(pact_interaction.find("description")).to(be_equal_to(file_interaction.find("description")));
                expect(pact_interaction.find("response")).to(be_equal_to(file_interaction.find("response")));

                let pact_request = pact_interaction.find("request").unwrap();
                let file_request = file_interaction.find("request").unwrap();
                expect(pact_request.find("method")).to(be_equal_to(file_request.find("method")));
                expect(pact_request.find("path")).to(be_equal_to(file_request.find("path")));
                expect(pact_request.find("headers")).to(be_equal_to(file_request.find("headers")));
                expect(pact_request.find("body")).to(be_equal_to(file_request.find("body")));
                expect(pact_request.find("query").unwrap().to_string().to_uppercase()).to(
                    be_equal_to(file_request.find("query").unwrap().to_string().to_uppercase()));
            }

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_lowercase_method() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_lowercase_method.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));

            let pact_interactions = pact_json.find("interactions").unwrap().as_array().unwrap();
            let pact_interactions_from_file = pact_json_from_file.find("interactions").unwrap().as_array().unwrap();
            expect(pact_interactions.len()).to(be_equal_to(pact_interactions_from_file.len()));

            for (pact_interaction, file_interaction) in pact_interactions.iter().zip(pact_interactions_from_file.iter()) {
                expect(pact_interaction.find("providerState")).to(be_equal_to(file_interaction.find("providerState")));
                expect(pact_interaction.find("description")).to(be_equal_to(file_interaction.find("description")));
                expect(pact_interaction.find("response")).to(be_equal_to(file_interaction.find("response")));

                let pact_request = pact_interaction.find("request").unwrap();
                let file_request = file_interaction.find("request").unwrap();
                expect(pact_request.find("method").unwrap().to_string()).to(be_equal_to(file_request.find("method").unwrap().to_string().to_uppercase()));
                expect(pact_request.find("path")).to(be_equal_to(file_request.find("path")));
                expect(pact_request.find("headers")).to(be_equal_to(file_request.find("headers")));
                expect(pact_request.find("body")).to(be_equal_to(file_request.find("body")));
                // This is a V3 pact, so we can't load the query string
                expect(pact_request.find("query")).to(be_none());
            }

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("3.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

// test_pact_matchers.json
// test_pact_matchers_old_format.json
// test_pact_no_bodies.json
// test_pact_no_metadata.json
// test_pact_no_spec_version.json
// test_pact_no_version.json
// test_pact_query_old_format.json
// test_pact_v3.json
// test_pact_with_bodies.json
// v1-pact.json
// v2-pact.json
// v2_pact_query.json
// v3-message-pact.json
// v3-pact.json
<commit_msg>added some additional pact loading tests<commit_after>#[macro_use] extern crate pact_matching;
extern crate rustc_serialize;
#[macro_use(expect)] extern crate expectest;
#[macro_use] extern crate p_macro;

mod spec_testcases;

use pact_matching::models::*;
use std::path::Path;
use expectest::prelude::*;
use rustc_serialize::json::Json;
use std::fs::File;

#[test]
fn test_load_pact() {
    let pact_file = Path::new(file!()).parent().unwrap().join("pact.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification")).to(be_none());
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_pact_encoded_query() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_encoded_query.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));

            let pact_interactions = pact_json.find("interactions").unwrap().as_array().unwrap();
            let pact_interactions_from_file = pact_json_from_file.find("interactions").unwrap().as_array().unwrap();
            expect(pact_interactions.len()).to(be_equal_to(pact_interactions_from_file.len()));

            for (pact_interaction, file_interaction) in pact_interactions.iter().zip(pact_interactions_from_file.iter()) {
                expect(pact_interaction.find("providerState")).to(be_equal_to(file_interaction.find("providerState")));
                expect(pact_interaction.find("description")).to(be_equal_to(file_interaction.find("description")));
                expect(pact_interaction.find("response")).to(be_equal_to(file_interaction.find("response")));

                let pact_request = pact_interaction.find("request").unwrap();
                let file_request = file_interaction.find("request").unwrap();
                expect(pact_request.find("method")).to(be_equal_to(file_request.find("method")));
                expect(pact_request.find("path")).to(be_equal_to(file_request.find("path")));
                expect(pact_request.find("headers")).to(be_equal_to(file_request.find("headers")));
                expect(pact_request.find("body")).to(be_equal_to(file_request.find("body")));
                expect(pact_request.find("query").unwrap().to_string().to_uppercase()).to(
                    be_equal_to(file_request.find("query").unwrap().to_string().to_uppercase()));
            }

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_lowercase_method() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_lowercase_method.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));

            let pact_interactions = pact_json.find("interactions").unwrap().as_array().unwrap();
            let pact_interactions_from_file = pact_json_from_file.find("interactions").unwrap().as_array().unwrap();
            expect(pact_interactions.len()).to(be_equal_to(pact_interactions_from_file.len()));

            for (pact_interaction, file_interaction) in pact_interactions.iter().zip(pact_interactions_from_file.iter()) {
                expect(pact_interaction.find("providerState")).to(be_equal_to(file_interaction.find("providerState")));
                expect(pact_interaction.find("description")).to(be_equal_to(file_interaction.find("description")));
                expect(pact_interaction.find("response")).to(be_equal_to(file_interaction.find("response")));

                let pact_request = pact_interaction.find("request").unwrap();
                let file_request = file_interaction.find("request").unwrap();
                expect(pact_request.find("method").unwrap().to_string()).to(be_equal_to(file_request.find("method").unwrap().to_string().to_uppercase()));
                expect(pact_request.find("path")).to(be_equal_to(file_request.find("path")));
                expect(pact_request.find("headers")).to(be_equal_to(file_request.find("headers")));
                expect(pact_request.find("body")).to(be_equal_to(file_request.find("body")));
                // This is a V3 pact, so we can't load the query string
                expect(pact_request.find("query")).to(be_none());
            }

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("3.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_no_bodies() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_no_bodies.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            for pact_interaction in pact.interactions.clone() {
                expect(pact_interaction.request.body).to(be_equal_to(OptionalBody::Missing));
                expect(pact_interaction.response.body).to(be_equal_to(OptionalBody::Missing));
            }

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_no_metadata() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_no_metadata.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification")).to(be_none());
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_no_spec_version() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_no_spec_version.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification")).to(be_none());
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_no_version() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_no_version.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("null"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
            expect(pact.specification_version.clone()).to(be_equal_to(PactSpecification::Unknown));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_query_old_format() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_query_old_format.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

#[test]
fn test_load_test_pact_with_bodies() {
    let pact_file = Path::new(file!()).parent().unwrap().join("test_pact_with_bodies.json");
    let pact_result = Pact::read_pact(&pact_file);

    match pact_result {
        Ok(ref pact) => {
            let mut f = File::open(pact_file).unwrap();
            let pact_json_from_file = Json::from_reader(&mut f).unwrap();
            let pact_json = pact.to_json();
            expect(pact_json.find("consumer")).to(be_equal_to(pact_json_from_file.find("consumer")));
            expect(pact_json.find("provider")).to(be_equal_to(pact_json_from_file.find("provider")));
            expect(pact_json.find("interactions")).to(be_equal_to(pact_json_from_file.find("interactions")));

            expect(pact.metadata.get("pact-specification").unwrap().get("version")).to(be_some().value("2.0.0"));
            let metadata = pact_json.find("metadata").unwrap().as_object().unwrap();
            let expected_keys : Vec<String> = vec![s!("pact-jvm"), s!("pact-rust"), s!("pact-specification")];
            expect(metadata.keys().cloned().collect::<Vec<String>>()).to(be_equal_to(expected_keys));
            expect(metadata.get("pact-specification").unwrap().to_string()).to(be_equal_to(s!("{\"version\":\"1.0.0\"}")));
        },
        Err(err) => panic!("Failed to load pact from '{:?}' - {}", pact_file, err)
    }
}

// v1-pact.json
// v2-pact.json
// v2_pact_query.json
// v3-message-pact.json
// v3-pact.json
// test_pact_matchers.json
// test_pact_matchers_old_format.json
// test_pact_v3.json
<|endoftext|>


<commit_before>use num_complex::Complex;
use num_traits::Zero;

use crate::common::{verify_length, verify_length_divisible, FFTnum};

use crate::algorithm::butterflies::{
    Butterfly16, Butterfly2, Butterfly4, Butterfly8, FFTButterfly,
};
use crate::twiddles;
use crate::{IsInverse, Length, FFT};

/// FFT algorithm optimized for power-of-two sizes
///
/// ~~~
/// // Computes a forward FFT of size 4096
/// use rustfft::algorithm::Radix4;
/// use rustfft::FFT;
/// use rustfft::num_complex::Complex;
/// use rustfft::num_traits::Zero;
///
/// let mut input:  Vec<Complex<f32>> = vec![Zero::zero(); 4096];
/// let mut output: Vec<Complex<f32>> = vec![Zero::zero(); 4096];
///
/// let fft = Radix4::new(4096, false);
/// fft.process(&mut input, &mut output);
/// ~~~

pub struct Radix4<T> {
    twiddles: Box<[Complex<T>]>,
    butterfly8: Butterfly8<T>,
    butterfly16: Butterfly16<T>,
    len: usize,
    inverse: bool,
}

impl<T: FFTnum> Radix4<T> {
    /// Preallocates necessary arrays and precomputes necessary data to efficiently compute the power-of-two FFT
    pub fn new(len: usize, inverse: bool) -> Self {
        assert!(
            len.is_power_of_two(),
            "Radix4 algorithm requires a power-of-two input size. Got {}",
            len
        );

        // precompute the twiddle factors this algorithm will use.
        // we're doing the same precomputation of twiddle factors as the mixed radix algorithm where width=4 and height=len/4
        // but mixed radix only does one step and then calls itself recusrively, and this algorithm does every layer all the way down
        // so we're going to pack all the "layers" of twiddle factors into a single array, starting with the bottom and going up
        let num_bits = len.trailing_zeros();
        let mut twiddle_stride = if num_bits % 2 == 0 {
            len / 64
        } else {
            len / 32
        };

        let mut twiddle_factors = Vec::with_capacity(len * 2);
        while twiddle_stride > 0 {
            let num_rows = len / (twiddle_stride * 4);
            for i in 0..num_rows {
                for k in 1..4 {
                    let twiddle = twiddles::single_twiddle(i * k * twiddle_stride, len, inverse);
                    twiddle_factors.push(twiddle);
                }
            }
            twiddle_stride >>= 2;
        }

        Self {
            twiddles: twiddle_factors.into_boxed_slice(),
            butterfly8: Butterfly8::new(inverse),
            butterfly16: Butterfly16::new(inverse),
            len,
            inverse,
        }
    }

    fn perform_fft(&self, signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
        match self.len() {
            0 | 1 => spectrum.copy_from_slice(signal),
            2 => {
                spectrum.copy_from_slice(signal);
                unsafe { Butterfly2::new(self.inverse).process_inplace(spectrum) }
            }
            4 => {
                spectrum.copy_from_slice(signal);
                unsafe { Butterfly4::new(self.inverse).process_inplace(spectrum) }
            }
            _ => {
                // copy the data into the spectrum vector
                prepare_radix4(signal.len(), signal, spectrum, 1);

                // perform the butterflies. the butterfly size depends on the input size
                let num_bits = signal.len().trailing_zeros();
                let mut current_size = if num_bits % 2 == 0 {
                    unsafe { self.butterfly16.process_multi_inplace(spectrum) };

                    // for the cross-ffts we want to to start off with a size of 64 (16 * 4)
                    64
                } else {
                    unsafe { self.butterfly8.process_multi_inplace(spectrum) };

                    // for the cross-ffts we want to to start off with a size of 32 (8 * 4)
                    32
                };

                let mut layer_twiddles: &[Complex<T>] = &self.twiddles;

                // now, perform all the cross-FFTs, one "layer" at a time
                while current_size <= signal.len() {
                    let num_rows = signal.len() / current_size;

                    for i in 0..num_rows {
                        unsafe {
                            butterfly_4(
                                &mut spectrum[i * current_size..],
                                layer_twiddles,
                                current_size / 4,
                                self.inverse,
                            )
                        }
                    }

                    //skip past all the twiddle factors used in this layer
                    let twiddle_offset = (current_size * 3) / 4;
                    layer_twiddles = &layer_twiddles[twiddle_offset..];

                    current_size *= 4;
                }
            }
        }
    }
}

impl<T: FFTnum> FFT<T> for Radix4<T> {
    fn process(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length(input, output, self.len());

        self.perform_fft(input, output);
    }
    fn process_multi(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length_divisible(input, output, self.len());

        for (in_chunk, out_chunk) in input
            .chunks_mut(self.len())
            .zip(output.chunks_mut(self.len()))
        {
            self.perform_fft(in_chunk, out_chunk);
        }
    }
}
impl<T> Length for Radix4<T> {
    #[inline(always)]
    fn len(&self) -> usize {
        self.len
    }
}
impl<T> IsInverse for Radix4<T> {
    #[inline(always)]
    fn is_inverse(&self) -> bool {
        self.inverse
    }
}

// after testing an iterative bit reversal algorithm, this recursive algorithm
// was almost an order of magnitude faster at setting up
fn prepare_radix4<T: FFTnum>(
    size: usize,
    signal: &[Complex<T>],
    spectrum: &mut [Complex<T>],
    stride: usize,
) {
    match size {
        16 => unsafe {
            for i in 0..16 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        8 => unsafe {
            for i in 0..8 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        4 => unsafe {
            for i in 0..4 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        2 => unsafe {
            for i in 0..2 {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        _ => {
            for i in 0..4 {
                prepare_radix4(
                    size / 4,
                    &signal[i * stride..],
                    &mut spectrum[i * (size / 4)..],
                    stride * 4,
                );
            }
        }
    }
}

unsafe fn butterfly_4<T: FFTnum>(
    data: &mut [Complex<T>],
    twiddles: &[Complex<T>],
    num_ffts: usize,
    inverse: bool,
) {
    let mut idx = 0usize;
    let mut tw_idx = 0usize;
    let mut scratch: [Complex<T>; 6] = [Zero::zero(); 6];
    for _ in 0..num_ffts {
        scratch[0] = data.get_unchecked(idx + 1 * num_ffts) * twiddles[tw_idx];
        scratch[1] = data.get_unchecked(idx + 2 * num_ffts) * twiddles[tw_idx + 1];
        scratch[2] = data.get_unchecked(idx + 3 * num_ffts) * twiddles[tw_idx + 2];
        scratch[5] = data.get_unchecked(idx) - scratch[1];
        *data.get_unchecked_mut(idx) = data.get_unchecked(idx) + scratch[1];
        scratch[3] = scratch[0] + scratch[2];
        scratch[4] = scratch[0] - scratch[2];
        *data.get_unchecked_mut(idx + 2 * num_ffts) = data.get_unchecked(idx) - scratch[3];
        *data.get_unchecked_mut(idx) = data.get_unchecked(idx) + scratch[3];
        if inverse {
            data.get_unchecked_mut(idx + num_ffts).re = scratch[5].re - scratch[4].im;
            data.get_unchecked_mut(idx + num_ffts).im = scratch[5].im + scratch[4].re;
            data.get_unchecked_mut(idx + 3 * num_ffts).re = scratch[5].re + scratch[4].im;
            data.get_unchecked_mut(idx + 3 * num_ffts).im = scratch[5].im - scratch[4].re;
        } else {
            data.get_unchecked_mut(idx + num_ffts).re = scratch[5].re + scratch[4].im;
            data.get_unchecked_mut(idx + num_ffts).im = scratch[5].im - scratch[4].re;
            data.get_unchecked_mut(idx + 3 * num_ffts).re = scratch[5].re - scratch[4].im;
            data.get_unchecked_mut(idx + 3 * num_ffts).im = scratch[5].im + scratch[4].re;
        }

        tw_idx += 3;
        idx += 1;
    }
}

#[cfg(test)]
mod unit_tests {
    use super::*;
    use crate::test_utils::check_fft_algorithm;

    #[test]
    fn test_radix4() {
        for pow in 0..8 {
            let len = 1 << pow;
            test_radix4_with_length(len, false);
            test_radix4_with_length(len, true);
        }
    }

    fn test_radix4_with_length(len: usize, inverse: bool) {
        let fft = Radix4::new(len, inverse);

        check_fft_algorithm(&fft, len, inverse);
    }
}
<commit_msg>minor refactoring<commit_after>use num_complex::Complex;
use num_traits::Zero;

use crate::common::{verify_length, verify_length_divisible, FFTnum};

use crate::algorithm::butterflies::{
    Butterfly16, Butterfly2, Butterfly4, Butterfly8, FFTButterfly,
};
use crate::twiddles;
use crate::{IsInverse, Length, FFT};

/// FFT algorithm optimized for power-of-two sizes
///
/// ~~~
/// // Computes a forward FFT of size 4096
/// use rustfft::algorithm::Radix4;
/// use rustfft::FFT;
/// use rustfft::num_complex::Complex;
/// use rustfft::num_traits::Zero;
///
/// let mut input:  Vec<Complex<f32>> = vec![Zero::zero(); 4096];
/// let mut output: Vec<Complex<f32>> = vec![Zero::zero(); 4096];
///
/// let fft = Radix4::new(4096, false);
/// fft.process(&mut input, &mut output);
/// ~~~

pub struct Radix4<T> {
    twiddles: Box<[Complex<T>]>,
    butterfly8: Butterfly8<T>,
    butterfly16: Butterfly16<T>,
    len: usize,
    inverse: bool,
}

impl<T: FFTnum> Radix4<T> {
    /// Preallocates necessary arrays and precomputes necessary data to efficiently compute the power-of-two FFT
    pub fn new(len: usize, inverse: bool) -> Self {
        assert!(
            len.is_power_of_two(),
            "Radix4 algorithm requires a power-of-two input size. Got {}",
            len
        );

        // precompute the twiddle factors this algorithm will use.
        // we're doing the same precomputation of twiddle factors as the mixed radix algorithm where width=4 and height=len/4
        // but mixed radix only does one step and then calls itself recusrively, and this algorithm does every layer all the way down
        // so we're going to pack all the "layers" of twiddle factors into a single array, starting with the bottom and going up
        let num_bits = len.trailing_zeros();
        let mut twiddle_stride = if num_bits % 2 == 0 {
            len / 64
        } else {
            len / 32
        };

        let mut twiddle_factors = Vec::with_capacity(len * 2);
        while twiddle_stride > 0 {
            let num_rows = len / (twiddle_stride * 4);
            for i in 0..num_rows {
                for k in 1..4 {
                    let twiddle = twiddles::single_twiddle(i * k * twiddle_stride, len, inverse);
                    twiddle_factors.push(twiddle);
                }
            }
            twiddle_stride >>= 2;
        }

        Self {
            twiddles: twiddle_factors.into_boxed_slice(),
            butterfly8: Butterfly8::new(inverse),
            butterfly16: Butterfly16::new(inverse),
            len,
            inverse,
        }
    }

    fn perform_fft(&self, signal: &[Complex<T>], spectrum: &mut [Complex<T>]) {
        match self.len() {
            0 | 1 => spectrum.copy_from_slice(signal),
            2 => {
                spectrum.copy_from_slice(signal);
                unsafe { Butterfly2::new(self.inverse).process_inplace(spectrum) }
            }
            4 => {
                spectrum.copy_from_slice(signal);
                unsafe { Butterfly4::new(self.inverse).process_inplace(spectrum) }
            }
            _ => {
                // copy the data into the spectrum vector
                prepare_radix4(signal.len(), signal, spectrum, 1);

                // perform the butterflies. the butterfly size depends on the input size
                let num_bits = signal.len().trailing_zeros();
                let mut current_size = if num_bits % 2 == 0 {
                    unsafe { self.butterfly16.process_multi_inplace(spectrum) };

                    // for the cross-ffts we want to to start off with a size of 64 (16 * 4)
                    64
                } else {
                    unsafe { self.butterfly8.process_multi_inplace(spectrum) };

                    // for the cross-ffts we want to to start off with a size of 32 (8 * 4)
                    32
                };

                let mut layer_twiddles: &[Complex<T>] = &self.twiddles;

                // now, perform all the cross-FFTs, one "layer" at a time
                while current_size <= signal.len() {
                    let num_rows = signal.len() / current_size;

                    for i in 0..num_rows {
                        unsafe {
                            butterfly_4(
                                &mut spectrum[i * current_size..],
                                layer_twiddles,
                                current_size / 4,
                                self.inverse,
                            )
                        }
                    }

                    //skip past all the twiddle factors used in this layer
                    let twiddle_offset = (current_size * 3) / 4;
                    layer_twiddles = &layer_twiddles[twiddle_offset..];

                    current_size *= 4;
                }
            }
        }
    }
}

impl<T: FFTnum> FFT<T> for Radix4<T> {
    fn process(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length(input, output, self.len());

        self.perform_fft(input, output);
    }
    fn process_multi(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length_divisible(input, output, self.len());

        for (in_chunk, out_chunk) in input
            .chunks_mut(self.len())
            .zip(output.chunks_mut(self.len()))
        {
            self.perform_fft(in_chunk, out_chunk);
        }
    }
}
impl<T> Length for Radix4<T> {
    #[inline(always)]
    fn len(&self) -> usize {
        self.len
    }
}
impl<T> IsInverse for Radix4<T> {
    #[inline(always)]
    fn is_inverse(&self) -> bool {
        self.inverse
    }
}

// after testing an iterative bit reversal algorithm, this recursive algorithm
// was almost an order of magnitude faster at setting up
fn prepare_radix4<T: FFTnum>(
    size: usize,
    signal: &[Complex<T>],
    spectrum: &mut [Complex<T>],
    stride: usize,
) {
    match size {
        2 | 4 | 8 | 16 => unsafe {
            for i in 0..size {
                *spectrum.get_unchecked_mut(i) = *signal.get_unchecked(i * stride);
            }
        },
        _ => {
            for i in 0..4 {
                prepare_radix4(
                    size / 4,
                    &signal[i * stride..],
                    &mut spectrum[i * (size / 4)..],
                    stride * 4,
                );
            }
        }
    }
}

unsafe fn butterfly_4<T: FFTnum>(
    data: &mut [Complex<T>],
    twiddles: &[Complex<T>],
    num_ffts: usize,
    inverse: bool,
) {
    let mut idx = 0usize;
    let mut tw_idx = 0usize;
    let mut scratch: [Complex<T>; 6] = [Zero::zero(); 6];
    for _ in 0..num_ffts {
        scratch[0] = data.get_unchecked(idx + 1 * num_ffts) * twiddles[tw_idx];
        scratch[1] = data.get_unchecked(idx + 2 * num_ffts) * twiddles[tw_idx + 1];
        scratch[2] = data.get_unchecked(idx + 3 * num_ffts) * twiddles[tw_idx + 2];
        scratch[5] = data.get_unchecked(idx) - scratch[1];
        *data.get_unchecked_mut(idx) = data.get_unchecked(idx) + scratch[1];
        scratch[3] = scratch[0] + scratch[2];
        scratch[4] = scratch[0] - scratch[2];
        *data.get_unchecked_mut(idx + 2 * num_ffts) = data.get_unchecked(idx) - scratch[3];
        *data.get_unchecked_mut(idx) = data.get_unchecked(idx) + scratch[3];
        if inverse {
            data.get_unchecked_mut(idx + num_ffts).re = scratch[5].re - scratch[4].im;
            data.get_unchecked_mut(idx + num_ffts).im = scratch[5].im + scratch[4].re;
            data.get_unchecked_mut(idx + 3 * num_ffts).re = scratch[5].re + scratch[4].im;
            data.get_unchecked_mut(idx + 3 * num_ffts).im = scratch[5].im - scratch[4].re;
        } else {
            data.get_unchecked_mut(idx + num_ffts).re = scratch[5].re + scratch[4].im;
            data.get_unchecked_mut(idx + num_ffts).im = scratch[5].im - scratch[4].re;
            data.get_unchecked_mut(idx + 3 * num_ffts).re = scratch[5].re - scratch[4].im;
            data.get_unchecked_mut(idx + 3 * num_ffts).im = scratch[5].im + scratch[4].re;
        }

        tw_idx += 3;
        idx += 1;
    }
}

#[cfg(test)]
mod unit_tests {
    use super::*;
    use crate::test_utils::check_fft_algorithm;

    #[test]
    fn test_radix4() {
        for pow in 0..8 {
            let len = 1 << pow;
            test_radix4_with_length(len, false);
            test_radix4_with_length(len, true);
        }
    }

    fn test_radix4_with_length(len: usize, inverse: bool) {
        let fft = Radix4::new(len, inverse);

        check_fft_algorithm(&fft, len, inverse);
    }
}
<|endoftext|>


<commit_before>use num::traits::{ToPrimitive, NumCast};
use std::marker::{PhantomData};
use std::collections::{VecMap};
use std::fmt::{Debug};
use image::{GenericImage, SubImage, Pixel};
use ::geom::{V2};
use super::canvas::{CanvasBuilder, Image};

/// A cache that loads sprites and stores them efficiently indexed by
/// enum constants given by the user.
///
/// Use an enum that contains names for all the sprites as the key type.
pub struct SpriteCache<T> {
    cache: VecMap<Image>,
    // Lock the cache into the specific enum type even though it doesn't
    // show up in the actual implementation, just to keep usage clearer.
    phantom: PhantomData<T>,
}

impl<T: Debug+Copy+SpriteKey> SpriteCache<T> {
    pub fn new() -> SpriteCache<T> {
        SpriteCache {
            cache: VecMap::new(),
            phantom: PhantomData,
        }
    }

    /// Try to retrieve an image with the given identifier.
    pub fn get(&self, key: T) -> Option<Image> {
        self.cache.get(&SpriteCache::index(key)).map(|&x| x)
    }

    /// Try to retrieve an image some steps ahead of the given key.
    ///
    /// Useful for animations and variants where there are deterministic
    /// consecutive sequences of frames and you don't want to hardcode
    /// every frame as a separate constant.
    pub fn get_nth(&self, key: T, offset: usize) -> Option<Image> {
        self.cache.get(&(SpriteCache::index(key) + offset)).map(|&x| x)
    }

    /// Add an image to the CanvasBuilder atlas for the given identifier key.
    ///
    /// Trying to add multiple sprites with the same key is considered a
    /// bug and will cause a panic.
    pub fn add<P, I>(&mut self, builder: &mut CanvasBuilder, key: T, offset: V2<i32>, image: &I)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P>
    {
        let idx = SpriteCache::index(key);
        assert!(self.cache.get(&idx).is_none(), format!("Adding sprite {:?} twice", key));

        self.cache.insert(idx, builder.add_image(offset, image));
    }

    /// Add multiple images from a sprite sheet.
    ///
    /// The sheet images are assumed to be in a grid with sprite_size
    /// cells. The sheet is read from top to bottom in left-to-right
    /// rows. Sprites are read and given cache keys corresponding to the
    /// values in the keys Vec as long as there are items left in keys.
    /// If there are more keys in the keys Vec than there are sprites in
    /// the sprite sheet, the function will panic.
    pub fn batch_add<P, I>(&mut self, builder: &mut CanvasBuilder, offset: V2<i32>, sprite_size: V2<u32>,
                           sprite_sheet: &mut I, keys: Vec<T>)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P> + 'static
    {
        let (sw, sh) = sprite_sheet.dimensions();
        let V2(w, h) = sprite_size;
        let (cols, rows) = (sw / sprite_size.0, sh / sprite_size.1);
        assert!(keys.len() as u32 <= rows * cols, "More keys specified than there are sprites on the sheet");
        for i in 0..keys.len() {
            let sub = SubImage::new(sprite_sheet, (i as u32 % cols) * w, (i as u32 / cols) * h, w, h);
            self.add(builder, keys[i], offset, &sub);
        }
    }

    fn index(key: T) -> usize {
        key.to_usize()
    }
}

// TODO: Find a way to convert the type param to usize that can use a
// derive-statment or something, instead of needing the boilerplate of
// implementing this trait...
pub trait SpriteKey {
    fn to_usize(self) -> usize;
}

impl<T: ToPrimitive> SpriteKey for T {
    fn to_usize(self) -> usize {
        NumCast::from(self).unwrap()
    }
}
<commit_msg>Use HashMap in SpriteCache since VecMap is unstable<commit_after>use num::traits::{ToPrimitive, NumCast};
use std::marker::{PhantomData};
use std::collections::{HashMap};
use std::fmt::{Debug};
use image::{GenericImage, SubImage, Pixel};
use ::geom::{V2};
use super::canvas::{CanvasBuilder, Image};

/// A cache that loads sprites and stores them efficiently indexed by
/// enum constants given by the user.
///
/// Use an enum that contains names for all the sprites as the key type.
pub struct SpriteCache<T> {
    // TODO: This should be VecMap! Change when VecMap is stable.
    cache: HashMap<usize, Image>,
    // Lock the cache into the specific enum type even though it doesn't
    // show up in the actual implementation, just to keep usage clearer.
    phantom: PhantomData<T>,
}

impl<T: Debug+Copy+SpriteKey> SpriteCache<T> {
    pub fn new() -> SpriteCache<T> {
        SpriteCache {
            cache: HashMap::new(),
            phantom: PhantomData,
        }
    }

    /// Try to retrieve an image with the given identifier.
    pub fn get(&self, key: T) -> Option<Image> {
        self.cache.get(&SpriteCache::index(key)).map(|&x| x)
    }

    /// Try to retrieve an image some steps ahead of the given key.
    ///
    /// Useful for animations and variants where there are deterministic
    /// consecutive sequences of frames and you don't want to hardcode
    /// every frame as a separate constant.
    pub fn get_nth(&self, key: T, offset: usize) -> Option<Image> {
        self.cache.get(&(SpriteCache::index(key) + offset)).map(|&x| x)
    }

    /// Add an image to the CanvasBuilder atlas for the given identifier key.
    ///
    /// Trying to add multiple sprites with the same key is considered a
    /// bug and will cause a panic.
    pub fn add<P, I>(&mut self, builder: &mut CanvasBuilder, key: T, offset: V2<i32>, image: &I)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P>
    {
        let idx = SpriteCache::index(key);
        assert!(self.cache.get(&idx).is_none(), format!("Adding sprite {:?} twice", key));

        self.cache.insert(idx, builder.add_image(offset, image));
    }

    /// Add multiple images from a sprite sheet.
    ///
    /// The sheet images are assumed to be in a grid with sprite_size
    /// cells. The sheet is read from top to bottom in left-to-right
    /// rows. Sprites are read and given cache keys corresponding to the
    /// values in the keys Vec as long as there are items left in keys.
    /// If there are more keys in the keys Vec than there are sprites in
    /// the sprite sheet, the function will panic.
    pub fn batch_add<P, I>(&mut self, builder: &mut CanvasBuilder, offset: V2<i32>, sprite_size: V2<u32>,
                           sprite_sheet: &mut I, keys: Vec<T>)
        where P: Pixel<Subpixel=u8> + 'static,
              I: GenericImage<Pixel=P> + 'static
    {
        let (sw, sh) = sprite_sheet.dimensions();
        let V2(w, h) = sprite_size;
        let (cols, rows) = (sw / sprite_size.0, sh / sprite_size.1);
        assert!(keys.len() as u32 <= rows * cols, "More keys specified than there are sprites on the sheet");
        for i in 0..keys.len() {
            let sub = SubImage::new(sprite_sheet, (i as u32 % cols) * w, (i as u32 / cols) * h, w, h);
            self.add(builder, keys[i], offset, &sub);
        }
    }

    fn index(key: T) -> usize {
        key.to_usize()
    }
}

// TODO: Find a way to convert the type param to usize that can use a
// derive-statment or something, instead of needing the boilerplate of
// implementing this trait...
pub trait SpriteKey {
    fn to_usize(self) -> usize;
}

impl<T: ToPrimitive> SpriteKey for T {
    fn to_usize(self) -> usize {
        NumCast::from(self).unwrap()
    }
}
<|endoftext|>


<commit_before>use crate::providers::{packet, MetadataProvider};
use mockito::{self, Matcher};

#[test]
fn test_boot_checkin() {
    let data = packet::PacketData {
        id: String::new(),
        hostname: String::new(),
        iqn: String::new(),
        plan: String::new(),
        facility: String::new(),
        tags: vec![],
        ssh_keys: vec![],
        network: packet::PacketNetworkInfo {
            interfaces: vec![],
            addresses: vec![],
            bonding: packet::PacketBondingMode { mode: 0 },
        },
        error: None,
        phone_home_url: mockito::server_url(),
    };
    let provider = packet::PacketProvider { data };

    let mock = mockito::mock("POST", "/")
        .match_header(
            "content-type",
            Matcher::Regex("application/json".to_string()),
        )
        .match_body("")
        .with_status(200)
        .create();

    let r = provider.boot_checkin();
    mock.assert();
    r.unwrap();

    mockito::reset();

    // Check error logic, but fail fast without re-trying.
    let client = crate::retry::Client::try_new().unwrap().max_retries(0);
    packet::PacketProvider::fetch_content(Some(client)).unwrap_err();
}

#[test]
fn test_packet_attributes() {
    let metadata = r#"{
        "id": "test-id",
        "hostname": "test-hostname",
        "iqn": "test-iqn",
        "plan": "test-plan",
        "facility": "test-facility",
        "tags": [],
        "ssh_keys": [],
        "network": {
            "interfaces": [],
            "addresses": [],
            "bonding": { "mode": 0 }
        },
        "phone_home_url": "test-url"
    }"#;

    let attributes = maplit::hashmap! {
        "PACKET_HOSTNAME".to_string() => "test-hostname".to_string(),
        "PACKET_PHONE_HOME_URL".to_string() => "test-url".to_string(),
        "PACKET_PLAN".to_string() => "test-plan".to_string(),
    };

    let _m = mockito::mock("GET", "/metadata")
        .with_status(200)
        .with_body(metadata)
        .create();

    let provider = packet::PacketProvider::try_new().unwrap();
    let v = provider.attributes().unwrap();

    assert_eq!(v, attributes);

    mockito::reset();

    // Check error logic, but fail fast without re-trying.
    let client = crate::retry::Client::try_new().unwrap().max_retries(0);
    packet::PacketProvider::fetch_content(Some(client)).unwrap_err();
}
<commit_msg>providers/packet: test IP address attributes<commit_after>use crate::providers::{packet, MetadataProvider};
use mockito::{self, Matcher};

#[test]
fn test_boot_checkin() {
    let data = packet::PacketData {
        id: String::new(),
        hostname: String::new(),
        iqn: String::new(),
        plan: String::new(),
        facility: String::new(),
        tags: vec![],
        ssh_keys: vec![],
        network: packet::PacketNetworkInfo {
            interfaces: vec![],
            addresses: vec![],
            bonding: packet::PacketBondingMode { mode: 0 },
        },
        error: None,
        phone_home_url: mockito::server_url(),
    };
    let provider = packet::PacketProvider { data };

    let mock = mockito::mock("POST", "/")
        .match_header(
            "content-type",
            Matcher::Regex("application/json".to_string()),
        )
        .match_body("")
        .with_status(200)
        .create();

    let r = provider.boot_checkin();
    mock.assert();
    r.unwrap();

    mockito::reset();

    // Check error logic, but fail fast without re-trying.
    let client = crate::retry::Client::try_new().unwrap().max_retries(0);
    packet::PacketProvider::fetch_content(Some(client)).unwrap_err();
}

#[test]
fn test_packet_attributes() {
    let metadata = r#"{
        "id": "test-id",
        "hostname": "test-hostname",
        "iqn": "test-iqn",
        "plan": "test-plan",
        "facility": "test-facility",
        "tags": [],
        "ssh_keys": [],
        "network": {
            "interfaces": [],
            "addresses": [
              {
                "id": "fde74ec8-bc24-43ca-a852-875bd6e10bee",
                "address_family": 4,
                "netmask": "255.255.255.254",
                "public": true,
                "management": true,
                "address": "147.0.0.1",
                "gateway": "147.0.0.0"
              },
              {
                "id": "3ae01206-b03a-4353-b04d-94747d36457e",
                "address_family": 6,
                "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
                "public": true,
                "management": true,
                "address": "2604:1380::1",
                "gateway": "2604:1380::0"
              },
              {
                "id": "bec04697-31fd-4a99-b1a9-cd1c7b88c810",
                "address_family": 4,
                "netmask": "255.255.255.254",
                "public": false,
                "management": true,
                "address": "10.0.0.1",
                "gateway": "10.0.0.0"
              },
              {
                "id": "38475859-389f-48ac-a855-f3ebdb82c565",
                "address_family": 6,
                "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe",
                "public": false,
                "management": true,
                "address": "fd00::1",
                "gateway": "fd00::0"
              }
            ],
            "bonding": { "mode": 0 }
        },
        "phone_home_url": "test-url"
    }"#;

    let attributes = maplit::hashmap! {
        "PACKET_HOSTNAME".to_string() => "test-hostname".to_string(),
        "PACKET_PHONE_HOME_URL".to_string() => "test-url".to_string(),
        "PACKET_PLAN".to_string() => "test-plan".to_string(),
        "PACKET_IPV4_PUBLIC_0".to_string() => "147.0.0.1".to_string(),
        "PACKET_IPV4_PRIVATE_0".to_string() => "10.0.0.1".to_string(),
        "PACKET_IPV6_PUBLIC_0".to_string() => "2604:1380::1".to_string(),
        "PACKET_IPV6_PRIVATE_0".to_string() => "fd00::1".to_string(),
    };

    let _m = mockito::mock("GET", "/metadata")
        .with_status(200)
        .with_body(metadata)
        .create();

    let provider = packet::PacketProvider::try_new().unwrap();
    let v = provider.attributes().unwrap();

    assert_eq!(v, attributes);

    mockito::reset();

    // Check error logic, but fail fast without re-trying.
    let client = crate::retry::Client::try_new().unwrap().max_retries(0);
    packet::PacketProvider::fetch_content(Some(client)).unwrap_err();
}
<|endoftext|>


<commit_before>// A unit struct
#[derive(Debug)]
struct Nil;

// A tuple struct
#[derive(Debug)]
struct Pair(i32, f32);

// A struct with two fields
#[derive(Debug)]
struct Point {
    x: f32,
    y: f32,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;
    println!("point coordinates: ({}, {})", my_x, my_y);

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };
    println!("Rectangle: {:?}", _rectangle);

    // Instantiate a unit struct
    let _nil = Nil;
    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    println!("Unit struct {:?}", _nil);

    // Access the fields of a tuple struct
    println!("pair contains {:?} and {:?}", pair.0, pair.1);
    println!("pair struct {:?}", pair);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}<commit_msg>Rust By Examples [RBE] - 3.1 Structures - activity - rect_area<commit_after>// A unit struct
#[derive(Debug)]
struct Nil;

// A tuple struct
#[derive(Debug)]
struct Pair(i32, f32);

// A struct with two fields
#[derive(Debug)]
struct Point {
    x: f32,
    y: f32,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

pub fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;
    println!("point coordinates: ({}, {})", my_x, my_y);

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };
    //println!("Rectangle: {:?}", _rectangle);

    // Instantiate a unit struct
    let _nil = Nil;
    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    println!("Unit struct {:?}", _nil);

    // Access the fields of a tuple struct
    println!("pair contains {:?} and {:?}", pair.0, pair.1);
    println!("pair struct {:?}", pair);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);

    // Calculates the area of a rectangle
    let rect: Rectangle = Rectangle{
        p1: Point{x:-2.0, y: 3.2},
        p2: Point{x: 3.2, y:-1.8},
    };
    println!("Rectangle Area: {:?}", rect_area(rect));
}

// Activity
// Calculates the area of a rectangle
fn rect_area(rect: Rectangle) -> f32 {
    1.0
}<|endoftext|>


<commit_before>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use futures;
use super::*;

pub type TransactionGuard <'a> = WriteGuard<'a, TransactionId, Transaction>;
pub type ChangedObjs = BTreeMap<u64, Vec<(Id, DataObject)>>;
pub type DataSiteClients = HashMap<u64, Arc<data_site::AsyncServiceClient>>;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
    AssertionError
}

#[derive(Clone)]
struct DataObject {
    server: u64,
    cell: Option<Cell>,
    new: bool
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError> | TMError;

    rpc prepare(tid: TransactionId) -> PrepareResult | TMError;
    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn server_id(&self) -> u64 {
        self.server.server_id
    }
    fn get_data_site(&self, server_id: u64) -> io::Result<Arc<data_site::AsyncServiceClient>> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok(self.data_sites .get(&server_id).unwrap().clone())
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(u64, Arc<data_site::AsyncServiceClient>)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => match self.get_data_site(id) {
                Ok(site) => Ok((id, site.clone())),
                Err(e) => Err(e)
            },
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.txn_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.txn_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<TransactionGuard, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
    fn changed_objs(&self, txn: &TransactionGuard) -> ChangedObjs {
        let mut changed_objs: BTreeMap<u64, Vec<(Id, DataObject)>> = BTreeMap::new();
        for (id, data_obj) in &txn.data {
            changed_objs.entry(data_obj.server).or_insert_with(|| Vec::new()).push((*id, data_obj.clone()));
        }
        changed_objs
    }
    fn data_sites(&self, changed_objs: &ChangedObjs) -> Result<DataSiteClients, TMError>  {
        let data_sites: HashMap<u64, _> = changed_objs.iter().map(|(server_id, _)| {
            (*server_id, self.get_data_site(*server_id))
        }).collect();
        if data_sites.iter().any(|(_, data_site)| { data_site.is_err() }) {
            return Err(TMError::CannotLocateCellServer)
        }
        Ok(data_sites.into_iter().map(
            |(server_id, data_site)| {
                (server_id, data_site.unwrap())
            }
        ).collect())
    }
    fn site_prepare(
        server: Arc<NebServer>,
        tid: &TransactionId,
        objs: &Vec<(Id, DataObject)>,
        data_site: &Arc<data_site::AsyncServiceClient>
    ) -> Box<futures::Future<Item = PrepareResult, Error = TMError>> {
        let self_server_id = server.server_id;
        let cell_ids: Vec<_> = objs.iter().map(|&(id, _)| id).collect();
        let res_future = data_site
            .prepare(&self_server_id, &server.txn_peer.clock.to_clock(), tid, &cell_ids)
            .map_err(|prepare_res| -> TMError {
                TMError::NoResponseFromCellServer
            })
            .map(move |prepare_res| -> PrepareResult {
                let prepare_res = prepare_res.unwrap();
                let payload = prepare_res.payload;
                server.txn_peer.clock.merge_with(&prepare_res.clock);
                match payload {
                    PrepareResult::Wait => {
                        return payload
                    },
                    _ => {
                        return payload
                    }
                }
            });
        Box::new(res_future)
    }
    fn sites_prepare(&self, tid: &TransactionId, txn: Transaction, changed_objs: &ChangedObjs, data_sites: DataSiteClients) {
        let prepare_futures: Vec<_> = changed_objs.iter().map(|(server, objs)| {
            let data_site = data_sites.get(&server).unwrap();
            TransactionManager::site_prepare(
                self.server.clone(),
                tid, objs,
                data_site
            )
        }).collect();
        let prepare_result = future::join_all(prepare_futures).wait();
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.txn_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        if let Some(dataObj) = txn.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server_id, server)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone()),
                                    new: false,
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None,
                                    new: false,
                                });
                            }
                            TransactionExecResult::Wait => {} // TODO: deal with wait
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                let have_cached_cell = txn.data.contains_key(id);
                if !have_cached_cell {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: Some(cell.clone()),
                        new: true,
                    });
                    Ok(TransactionExecResult::Accepted(()))
                } else {
                    let mut data_obj = txn.data.get_mut(id).unwrap();
                    if !data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellAlreadyExisted))
                    }
                    data_obj.cell = Some(cell.clone());
                    Ok(TransactionExecResult::Accepted(()))
                }
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let id = cell.id();
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                let cell = cell.clone();
                if txn.data.contains_key(&id) {
                    txn.data.get_mut(&id).unwrap().cell = Some(cell)
                } else {
                    txn.data.insert(id, DataObject {
                        server: server_id,
                        cell: Some(cell),
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                if txn.data.contains_key(&id) {
                    let data_obj = txn.data.get_mut(&id).unwrap();
                    if data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellDoesNotExisted))
                    }
                    data_obj.cell = None;
                } else {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: None,
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn prepare(&self, tid: &TransactionId) -> Result<PrepareResult, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let mut changed_objs = self.changed_objs(&txn);
        let data_sites = self.data_sites(&changed_objs)?;
        Err(TMError::CannotLocateCellServer)
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<commit_msg>rearrange futures so that we can break it when after await<commit_after>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use futures;
use super::*;

pub type TransactionGuard <'a> = WriteGuard<'a, TransactionId, Transaction>;
pub type ChangedObjs = BTreeMap<u64, Vec<(Id, DataObject)>>;
pub type DataSiteClients = HashMap<u64, Arc<data_site::AsyncServiceClient>>;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
    AssertionError
}

#[derive(Clone)]
struct DataObject {
    server: u64,
    cell: Option<Cell>,
    new: bool
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError> | TMError;

    rpc prepare(tid: TransactionId) -> PrepareResult | TMError;
    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn server_id(&self) -> u64 {
        self.server.server_id
    }
    fn get_data_site(&self, server_id: u64) -> io::Result<Arc<data_site::AsyncServiceClient>> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok(self.data_sites .get(&server_id).unwrap().clone())
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(u64, Arc<data_site::AsyncServiceClient>)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => match self.get_data_site(id) {
                Ok(site) => Ok((id, site.clone())),
                Err(e) => Err(e)
            },
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.txn_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.txn_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<TransactionGuard, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
    fn changed_objs(&self, txn: &TransactionGuard) -> ChangedObjs {
        let mut changed_objs: BTreeMap<u64, Vec<(Id, DataObject)>> = BTreeMap::new();
        for (id, data_obj) in &txn.data {
            changed_objs.entry(data_obj.server).or_insert_with(|| Vec::new()).push((*id, data_obj.clone()));
        }
        changed_objs
    }
    fn data_sites(&self, changed_objs: &ChangedObjs) -> Result<DataSiteClients, TMError>  {
        let data_sites: HashMap<u64, _> = changed_objs.iter().map(|(server_id, _)| {
            (*server_id, self.get_data_site(*server_id))
        }).collect();
        if data_sites.iter().any(|(_, data_site)| { data_site.is_err() }) {
            return Err(TMError::CannotLocateCellServer)
        }
        Ok(data_sites.into_iter().map(
            |(server_id, data_site)| {
                (server_id, data_site.unwrap())
            }
        ).collect())
    }
    fn site_prepare(
        server: Arc<NebServer>,
        tid: &TransactionId,
        objs: &Vec<(Id, DataObject)>,
        data_site: &Arc<data_site::AsyncServiceClient>
    ) -> Box<futures::Future<Item = PrepareResult, Error = TMError>> {
        let self_server_id = server.server_id;
        let cell_ids: Vec<_> = objs.iter().map(|&(id, _)| id).collect();
        let res_future = data_site
            .prepare(&self_server_id, &server.txn_peer.clock.to_clock(), tid, &cell_ids)
            .map_err(|_| -> TMError {
                TMError::NoResponseFromCellServer
            })
            .map(move |prepare_res| -> PrepareResult {
                let prepare_res = prepare_res.unwrap();
                server.txn_peer.clock.merge_with(&prepare_res.clock);
                prepare_res.payload
            })
            .then(|prepare_payload| {
                match prepare_payload {
                    Ok(payload) => {
                        match payload {
                            PrepareResult::Wait => {
                                return Ok(payload)
                            },
                            _ => {
                                return Ok(payload)
                            }
                        }
                    },
                    Err(e) => Err(e)
                }
            });
        Box::new(res_future)
    }
    fn sites_prepare(&self, tid: &TransactionId, txn: Transaction, changed_objs: &ChangedObjs, data_sites: DataSiteClients) {
        let prepare_futures: Vec<_> = changed_objs.iter().map(|(server, objs)| {
            let data_site = data_sites.get(&server).unwrap();
            TransactionManager::site_prepare(
                self.server.clone(), tid, objs, data_site
            )
        }).collect();
        let prepare_result = future::join_all(prepare_futures).wait();
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.txn_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        if let Some(dataObj) = txn.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server_id, server)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone()),
                                    new: false,
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                txn.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None,
                                    new: false,
                                });
                            }
                            TransactionExecResult::Wait => {} // TODO: deal with wait
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                let have_cached_cell = txn.data.contains_key(id);
                if !have_cached_cell {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: Some(cell.clone()),
                        new: true,
                    });
                    Ok(TransactionExecResult::Accepted(()))
                } else {
                    let mut data_obj = txn.data.get_mut(id).unwrap();
                    if !data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellAlreadyExisted))
                    }
                    data_obj.cell = Some(cell.clone());
                    Ok(TransactionExecResult::Accepted(()))
                }
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let id = cell.id();
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                let cell = cell.clone();
                if txn.data.contains_key(&id) {
                    txn.data.get_mut(&id).unwrap().cell = Some(cell)
                } else {
                    txn.data.insert(id, DataObject {
                        server: server_id,
                        cell: Some(cell),
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut txn = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(&id) {
            Some(server_id) => {
                if txn.data.contains_key(&id) {
                    let data_obj = txn.data.get_mut(&id).unwrap();
                    if data_obj.cell.is_none() {
                        return Ok(TransactionExecResult::Error(WriteError::CellDoesNotExisted))
                    }
                    data_obj.cell = None;
                } else {
                    txn.data.insert(*id, DataObject {
                        server: server_id,
                        cell: None,
                        new: false,
                    });
                }
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn prepare(&self, tid: &TransactionId) -> Result<PrepareResult, TMError> {
        let mut txn = self.get_transaction(tid)?;
        let mut changed_objs = self.changed_objs(&txn);
        let data_sites = self.data_sites(&changed_objs)?;
        Err(TMError::CannotLocateCellServer)
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<|endoftext|>


<commit_before>use hyper::client::{Client, Response};
use hyper::method::Method;

use std::process::{Child, Command, Stdio};
use std::thread;
use std::io::Read;
use std::sync::Mutex;

struct Bomb(Child);

// Don't leak child processes!
impl Drop for Bomb {
    fn drop(&mut self) {
        self.0.kill().expect("Leaking child process");

        if thread::panicking() {
            let mut s = String::new();
            let stdout = self.0.stdout.as_mut().unwrap();
            stdout.read_to_string(&mut s).unwrap();

            println!("Unparsed Stdout:\n{}", s);
        }
    }
}

pub fn response_for_method(method: Method, url: &str) -> Response {
    Client::new()
           .request(method, url)
           .send()
           .unwrap()
}

pub fn response_for(url: &str) -> Response {
    response_for_method(Method::Get, url)
}

pub fn read_body_to_string(res: &mut Response) -> String {
    let mut s = String::new();
    res.read_to_string(&mut s).unwrap();
    s
}

pub fn read_url(url: &str) -> String {
    let mut res = response_for(url);
    read_body_to_string(&mut res)
}

pub fn run_example<F>(name: &str, f: F)
where F: FnOnce(u16) {
    cargo_build(name);

    let command = format!("target/debug/examples/{}", name);
    let child = Command::new(&command)
                        .env("NICKEL_TEST_HARNESS", "1")
                        .stdout(Stdio::piped())
                        .spawn()
                        .unwrap();

    let mut bomb = Bomb(child);
    let port = parse_port(&mut bomb);

    f(port);
}

// We cannot use `cargo run --example foo` as when a test fails
// we can only send SIGKILL, which cargo doesn't propogate to the
// child process. Rust currently doesn't seem to give us a way to
// use SIGTERM.
//
// We do a full build call rather than just checking if the executable
// exists, as the dependancies may have changed and then a user running
// `cargo test --test foo` to run the integration tests only will not
// pick up the changes.
fn cargo_build(name: &str) {
    // Don't let cargo build in parallel, it can cause unnecessary test failures
    // https://github.com/rust-lang/cargo/issues/354
    //
    // NOTE: important to assign to variable or it'll drop instantly.
    let _lock = BUILD_LOCK.lock();

    let mut child = Command::new("cargo")
                            .arg("build")
                            .arg("--example")
                            .arg(name)
                            .env("NICKEL_TEST_HARNESS", "1")
                            .stdout(Stdio::piped())
                            .spawn()
                            .unwrap();
    child.wait().unwrap();
}

lazy_static! {
    static ref BUILD_LOCK : Mutex<()> = Mutex::new(());
}

fn parse_port(&mut Bomb(ref mut process): &mut Bomb) -> u16 {
    // stdout doesn't implement BufRead... *shrug*
    let stdout = process.stdout.as_mut().unwrap();

    let mut line = String::new();

    for c in stdout.bytes().map(|b| b.unwrap() as char) {
        if c == '\n' {
            // Check if it's the line we want
            if line.starts_with("Listening") {
                break
            } else {
                println!("Skipping Stdout line: {:?}", line);
                line.clear();
            }
        } else {
            line.push(c)
        }
    }

    let port = {
        let s = line.rsplitn(2, ':').next().unwrap();
        match s.parse() {
            Ok(port) => port,
            Err(e) => panic!("Failed to parse port from: {:?} : {:?}", line, e)
        }
    };

    println!("Parsed: port={} from {:?}", port, line);
    port
}
<commit_msg>fix(1.3): adjust example-tests to run on 1.3 on travis<commit_after>use hyper::client::{Client, Response};
use hyper::method::Method;

use std::process::{Child, Command, Stdio};
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::env;

struct Bomb(Child);

// Don't leak child processes!
impl Drop for Bomb {
    fn drop(&mut self) {
        match self.0.kill() {
            Ok(()) => {},
            Err(e) => panic!("Leaking child process: {:?}", e)
        }

        if thread::panicking() {
            let mut s = String::new();
            let stdout = self.0.stdout.as_mut().unwrap();
            stdout.read_to_string(&mut s).unwrap();

            println!("Unparsed Stdout:\n{}", s);
        }
    }
}

pub fn response_for_method(method: Method, url: &str) -> Response {
    Client::new()
           .request(method, url)
           .send()
           .unwrap()
}

pub fn response_for(url: &str) -> Response {
    response_for_method(Method::Get, url)
}

pub fn read_body_to_string(res: &mut Response) -> String {
    let mut s = String::new();
    res.read_to_string(&mut s).unwrap();
    s
}

pub fn read_url(url: &str) -> String {
    let mut res = response_for(url);
    read_body_to_string(&mut res)
}

pub fn run_example<F>(name: &str, f: F)
where F: FnOnce(u16) {
    cargo_build(name);

    let command = format!("target/debug/examples/{}", name);
    let child = Command::new(&command)
                        .env("NICKEL_TEST_HARNESS", "1")
                        .stdout(Stdio::piped())
                        .spawn()
                        .unwrap();

    let mut bomb = Bomb(child);
    let port = parse_port(&mut bomb);

    f(port);
}

// We cannot use `cargo run --example foo` as when a test fails
// we can only send SIGKILL, which cargo doesn't propogate to the
// child process. Rust currently doesn't seem to give us a way to
// use SIGTERM.
//
// We do a full build call rather than just checking if the executable
// exists, as the dependancies may have changed and then a user running
// `cargo test --test foo` to run the integration tests only will not
// pick up the changes.
fn cargo_build(name: &str) {
    // Don't let cargo build in parallel, it can cause unnecessary test failures
    // https://github.com/rust-lang/cargo/issues/354
    //
    // NOTE: important to assign to variable or it'll drop instantly.
    let _lock = BUILD_LOCK.lock();

    let mut command = Command::new("cargo");

    command.env("NICKEL_TEST_HARNESS", "1")
           .stdout(Stdio::piped())
           .arg("build")
           .arg("--example")
           .arg(name);

    // support for features passed in the env (as we do on travis)
    if let Some(arg) = env::var("FEATURES").ok() {
        for feature_arg in arg.split_whitespace() {
            command.arg(feature_arg);
        }
    }

    let mut child = command.spawn().unwrap();
    child.wait().unwrap();
}

lazy_static! {
    static ref BUILD_LOCK : Mutex<()> = Mutex::new(());
}

fn parse_port(&mut Bomb(ref mut process): &mut Bomb) -> u16 {
    // stdout doesn't implement BufRead... *shrug*
    let stdout = process.stdout.as_mut().unwrap();

    let mut line = String::new();

    for c in stdout.bytes().map(|b| b.unwrap() as char) {
        if c == '\n' {
            // Check if it's the line we want
            if line.starts_with("Listening") {
                break
            } else {
                println!("Skipping Stdout line: {:?}", line);
                line.clear();
            }
        } else {
            line.push(c)
        }
    }

    let port = {
        let s = line.rsplitn(2, ':').next().unwrap();
        match s.parse() {
            Ok(port) => port,
            Err(e) => panic!("Failed to parse port from: {:?} : {:?}", line, e)
        }
    };

    println!("Parsed: port={} from {:?}", port, line);
    port
}
<|endoftext|>


<commit_before>
extern crate regex;
extern crate gcc;
extern crate toml;

use std::borrow::ToOwned;
use std::collections::HashSet;
use std::env;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::{Path, PathBuf};
use regex::Regex;

// Fetch the 'package.exclude' list from our Cargo.toml file.  We'll
// use this to decide what sources to admit.
fn get_excluded_sources(manifest: &Path) -> HashSet<String> {
    let mut text = String::new();
    File::open(manifest).unwrap().read_to_string(&mut text).unwrap();
    let toml = toml::Parser::new(&text).parse().unwrap();
    let package = toml.get("package").unwrap().as_table().unwrap();
    let exclude = package.get("exclude").unwrap().as_slice().unwrap();
    exclude.iter().map(|e| {
        let str = e.as_str().unwrap();
        Path::new(str).file_name().unwrap().to_str().unwrap().to_string()
    }).collect()
}

// Get all the *.cc files in path that aren't excluded.
fn get_cc_files(dir: &Path, excluded: &HashSet<String>) -> Vec<PathBuf> {
    let cc_file = Regex::new(r"\.cc\z").unwrap();
    read_dir(dir).unwrap().map(|entry| {
        entry.unwrap().path()
    }).filter(|p| {
        let filename = p.file_name().unwrap().to_str().unwrap();
        cc_file.is_match(filename) && !excluded.contains(filename)
    }).map(|p| p.to_owned()).collect()
}

fn main() {
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let src = Path::new(&manifest_dir);

    // Decide what sources to build.
    let excluded = get_excluded_sources(&src.join("Cargo.toml"));
    let mut sources =
        get_cc_files(&src.join("cld2").join("internal"), &excluded);
    sources.push(src.join("src").join("wrapper.cpp"));

    // Convert the sources back to relative path &str values.
    // TODO: This required the unstable relative_from function.
    //let rel_sources: Vec<PathBuf> = sources.iter().map(|p| {
    //    p.relative_from(&src).unwrap().to_owned()
    //}).collect();

    // Run the build.
    let mut config = gcc::Config::new();
    config.cpp(true);
    config.include(&Path::new("cld2/public"));
    config.include(&Path::new("cld2/internal"));
    for f in sources.iter() {
        config.file(f);
    }
    config.compile("libcld2.a");
}
<commit_msg>Remove errors when building cld2 with gcc -std=c++11<commit_after>
extern crate regex;
extern crate gcc;
extern crate toml;

use std::borrow::ToOwned;
use std::collections::HashSet;
use std::env;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::{Path, PathBuf};
use regex::Regex;

// Fetch the 'package.exclude' list from our Cargo.toml file.  We'll
// use this to decide what sources to admit.
fn get_excluded_sources(manifest: &Path) -> HashSet<String> {
    let mut text = String::new();
    File::open(manifest).unwrap().read_to_string(&mut text).unwrap();
    let toml = toml::Parser::new(&text).parse().unwrap();
    let package = toml.get("package").unwrap().as_table().unwrap();
    let exclude = package.get("exclude").unwrap().as_slice().unwrap();
    exclude.iter().map(|e| {
        let str = e.as_str().unwrap();
        Path::new(str).file_name().unwrap().to_str().unwrap().to_string()
    }).collect()
}

// Get all the *.cc files in path that aren't excluded.
fn get_cc_files(dir: &Path, excluded: &HashSet<String>) -> Vec<PathBuf> {
    let cc_file = Regex::new(r"\.cc\z").unwrap();
    read_dir(dir).unwrap().map(|entry| {
        entry.unwrap().path()
    }).filter(|p| {
        let filename = p.file_name().unwrap().to_str().unwrap();
        cc_file.is_match(filename) && !excluded.contains(filename)
    }).map(|p| p.to_owned()).collect()
}

fn main() {
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let src = Path::new(&manifest_dir);

    // Decide what sources to build.
    let excluded = get_excluded_sources(&src.join("Cargo.toml"));
    let mut sources =
        get_cc_files(&src.join("cld2").join("internal"), &excluded);
    sources.push(src.join("src").join("wrapper.cpp"));

    // Convert the sources back to relative path &str values.
    // TODO: This required the unstable relative_from function.
    //let rel_sources: Vec<PathBuf> = sources.iter().map(|p| {
    //    p.relative_from(&src).unwrap().to_owned()
    //}).collect();

    // Run the build.
    let mut config = gcc::Config::new();
    config.cpp(true);
    config.flag("-Wno-error=narrowing");
    config.include(&Path::new("cld2/public"));
    config.include(&Path::new("cld2/internal"));
    for f in sources.iter() {
        config.file(f);
    }
    config.compile("libcld2.a");
}
<|endoftext|>