<commit_before>extern crate mockito;
extern crate sidekiq;
extern crate url;
#[macro_use]
extern crate maman;

use maman::{Page, Spider};
use sidekiq::create_redis_pool;

use std::collections::BTreeMap;
use std::env;
use std::str::FromStr;

use url::Url;

fn visit_page(input: &str) -> Spider {
    env::set_var("MAMAN_ENV", "test");
    let url = Url::parse("https://example.net/").unwrap();
    let redis_pool = create_redis_pool().unwrap();
    let mut spider = Spider::new(redis_pool, url.clone(), 0, Vec::new());
    let page = Page::new(
        url,
        input.to_string(),
        BTreeMap::new(),
        "200 OK".to_string(),
    );
    let tok = Spider::read_page(page, input);
    spider.visit_page(tok.sink);
    spider
}

#[test]
fn test_ignore_initial_url_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_ignore_fragment_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_ignore_mailto_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_new_with_fragment_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 2);
}

#[test]
fn test_other_domain_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 0);
}

#[test]
fn test_json_job_format() {
    env::set_var("MAMAN_ENV", "test");
    let input = "";
    let url = Url::parse("http://example.net/").unwrap();
    let mut headers = BTreeMap::new();
    headers.insert("content-type".to_string(), "text/html".to_string());
    let page = Page::new(
        url,
        input.to_string(),
        headers.clone(),
        "200 OK".to_string(),
    );
    let page_object = page.as_object();
    let job = page.to_job();
    assert_eq!(job.class, maman_name!());
    assert_eq!(job.retry, 25);
    assert_eq!(job.queue, maman_name!().to_string().to_lowercase());
    assert_eq!(job.args, vec![page_object]);
}

#[test]
fn test_integration() {
    use mockito::mock;
    let _r = mock("GET", "/robots.txt")
        .with_status(200)
        .with_header("content-type", "text/plain")
        .with_body("User-agent: *\nAllow: /")
        .create();
    let _m1 = mock("GET", "/")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("hello")
        .create();
    let _m2 = mock("GET", "/hello")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("world")
        .create();
    let _m3 = mock("GET", "/world")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("!")
        .create();
    let redis_pool = create_redis_pool().unwrap();
    let url = Url::parse(&mockito::server_url()).unwrap();
    let mut spider = Spider::new(redis_pool, url, 0, Vec::new());
    spider.crawl();
    assert_eq!(spider.visited_urls.len(), 3);
}

#[test]
fn test_integration_filter() {
    use mockito::mock;
    let _r = mock("GET", "/robots.txt")
        .with_status(200)
        .with_header("content-type", "text/plain")
        .with_body("User-agent: *\nAllow: /")
        .create();
    let _m1 = mock("GET", "/")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("hello")
        .create();
    let _m2 = mock("GET", "/hello")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("world")
        .create();
    let _m3 = mock("GET", "/world")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("!")
        .create();
    let redis_pool = create_redis_pool().unwrap();
    let url = Url::parse(&mockito::server_url()).unwrap();
    let mut spider = Spider::new(
        redis_pool,
        url,
        0,
        vec![mime::Mime::from_str("text/html").unwrap()],
    );
    spider.crawl();
    assert_eq!(spider.visited_urls.len(), 3);
}
<commit_msg>clippy: redundant clone<commit_after>extern crate mockito;
extern crate sidekiq;
extern crate url;
#[macro_use]
extern crate maman;

use maman::{Page, Spider};
use sidekiq::create_redis_pool;

use std::collections::BTreeMap;
use std::env;
use std::str::FromStr;

use url::Url;

fn visit_page(input: &str) -> Spider {
    env::set_var("MAMAN_ENV", "test");
    let url = Url::parse("https://example.net/").unwrap();
    let redis_pool = create_redis_pool().unwrap();
    let mut spider = Spider::new(redis_pool, url.clone(), 0, Vec::new());
    let page = Page::new(
        url,
        input.to_string(),
        BTreeMap::new(),
        "200 OK".to_string(),
    );
    let tok = Spider::read_page(page, input);
    spider.visit_page(tok.sink);
    spider
}

#[test]
fn test_ignore_initial_url_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_ignore_fragment_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_ignore_mailto_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 1);
}

#[test]
fn test_new_with_fragment_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 2);
}

#[test]
fn test_other_domain_link() {
    let input = "";
    let spider = visit_page(input);
    assert_eq!(spider.visited_urls.len(), 1);
    assert_eq!(spider.unvisited_urls.len(), 0);
}

#[test]
fn test_json_job_format() {
    env::set_var("MAMAN_ENV", "test");
    let input = "";
    let url = Url::parse("http://example.net/").unwrap();
    let mut headers = BTreeMap::new();
    headers.insert("content-type".to_string(), "text/html".to_string());
    let page = Page::new(url, input.to_string(), headers, "200 OK".to_string());
    let page_object = page.as_object();
    let job = page.to_job();
    assert_eq!(job.class, maman_name!());
    assert_eq!(job.retry, 25);
    assert_eq!(job.queue, maman_name!().to_string().to_lowercase());
    assert_eq!(job.args, vec![page_object]);
}

#[test]
fn test_integration() {
    use mockito::mock;
    let _r = mock("GET", "/robots.txt")
        .with_status(200)
        .with_header("content-type", "text/plain")
        .with_body("User-agent: *\nAllow: /")
        .create();
    let _m1 = mock("GET", "/")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("hello")
        .create();
    let _m2 = mock("GET", "/hello")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("world")
        .create();
    let _m3 = mock("GET", "/world")
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body("!")
        .create();
    let redis_pool = create_redis_pool().unwrap();
    let url = Url::parse(&mockito::server_url()).unwrap();
    let mut spider = Spider::new(redis_pool, url, 0, Vec::new());
    spider.crawl();
    assert_eq!(spider.visited_urls.len(), 3);
}

#[test]
fn test_integration_filter() {
    use mockito::mock;
    let _r = mock("GET", "/robots.txt")
        .with_status(200)
        .with_header("content-type", "text/plain")
        .with_body("User-agent: *\nAllow: /")
        .create();
    let _m1 = mock("GET", "/")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("hello")
        .create();
    let _m2 = mock("GET", "/hello")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("world")
        .create();
    let _m3 = mock("GET", "/world")
        .with_status(200)
        .with_header("content-type", "text/html; charset=utf-8")
        .with_body("!")
        .create();
    let redis_pool = create_redis_pool().unwrap();
    let url = Url::parse(&mockito::server_url()).unwrap();
    let mut spider = Spider::new(
        redis_pool,
        url,
        0,
        vec![mime::Mime::from_str("text/html").unwrap()],
    );
    spider.crawl();
    assert_eq!(spider.visited_urls.len(), 3);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;

use std::path::PathBuf;
use quickcheck::{quickcheck, TestResult};

extern crate hyphenation;
use hyphenation::{load, Language, Corpus, Hyphenation, Standard};

fn fiat_io(lang: Language) -> Corpus {
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.push("patterns");

    hyphenation::set_pattern_folder(path.as_path());
    load::language(lang).unwrap()
}

lazy_static! {
    static ref EN_US: Corpus = fiat_io(Language::English_US);
}

#[test]
fn collected_equals_original() {
    fn property(original: String) -> bool {
        let collected: String = original.hyphenate(&EN_US).collect();

        collected == original
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn opportunities_within_bounds() {
    fn property(s: String) -> bool {
        let os = s.opportunities(&EN_US);
        let l = s.len();

        os.iter().all(|&i| i < l)
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn punctuated_count() {
    fn property(s: String) -> bool {
        let l = s.chars().count();
        let os = s.opportunities(&EN_US);
        let h: String = s.hyphenate(&EN_US).punctuate().collect();

        h.chars().count() == l + os.len()
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn hyphenation_bounds() {
    fn property(s: String) -> TestResult {
        let ci: Vec<_> = s.char_indices().collect();
        let (l_min, r_min) = (&EN_US.left_min, &EN_US.right_min);
        let s_len = ci.len();
        if s_len < l_min + r_min {
            return TestResult::discard();
        }

        let os = s.opportunities(&EN_US);
        let ((l, _), (r, _)) = (ci[l_min - 1], ci[s_len - r_min]);
        let within_bounds = |&i| i > l && i <= r;

        TestResult::from_bool(os.iter().all(within_bounds))
    }

    quickcheck(property as fn(String) -> TestResult);
}

#[test]
fn basics() {
    let h1: Standard = "hyphenation".hyphenate(&EN_US);
    let h2: Standard = "project".hyphenate(&EN_US);
    let h3: Standard = "hypha".hyphenate(&EN_US);

    let v1: Vec<&str> = h1.clone().collect();
    let v2: Vec<&str> = h2.clone().collect();
    let v3: Vec<&str> = h3.clone().collect();
    assert_eq!(v1, vec!["hy", "phen", "ation"]);
    assert_eq!(v2, vec!["project"]);
    assert_eq!(v3, vec!["hy", "pha"]);

    let s1: String = h1.punctuate().collect();
    assert_eq!(s1, "hy\u{ad}phen\u{ad}ation".to_owned());
}
<commit_msg>Use the same setup for benchmarks and tests<commit_after>#[macro_use]
extern crate lazy_static;
extern crate quickcheck;

use std::fs::File;
use std::io::{BufRead, BufReader, Read};
use std::path::{Path, PathBuf};
use quickcheck::{quickcheck, TestResult};

extern crate hyphenation;
use hyphenation::{load, Language, Corpus, Hyphenation, Standard};

fn fiat_io(lang: Language) -> Corpus {
    hyphenation::set_pattern_folder(&DATAPATH.as_path());
    load::language(lang).unwrap()
}

lazy_static! {
    static ref DATAPATH: PathBuf = {
        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        path.push("patterns");

        path
    };

    static ref EN_US: Corpus = fiat_io(Language::English_US);

    static ref WORDS: Vec<String> = {
        let file = File::open(Path::new("/usr/share/dict/words")).unwrap();
        let words: Vec<_> = BufReader::new(file).lines().map(|l| l.unwrap()).collect();

        words
    };
}

#[test]
fn collected_equals_original() {
    fn property(original: String) -> bool {
        let collected: String = original.hyphenate(&EN_US).collect();

        collected == original
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn opportunities_within_bounds() {
    fn property(s: String) -> bool {
        let os = s.opportunities(&EN_US);
        let l = s.len();

        os.iter().all(|&i| i < l)
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn punctuated_count() {
    fn property(s: String) -> bool {
        let l = s.chars().count();
        let os = s.opportunities(&EN_US);
        let h: String = s.hyphenate(&EN_US).punctuate().collect();

        h.chars().count() == l + os.len()
    }

    quickcheck(property as fn(String) -> bool);
}

#[test]
fn hyphenation_bounds() {
    fn property(s: String) -> TestResult {
        let ci: Vec<_> = s.char_indices().collect();
        let (l_min, r_min) = (&EN_US.left_min, &EN_US.right_min);
        let s_len = ci.len();
        if s_len < l_min + r_min {
            return TestResult::discard();
        }

        let os = s.opportunities(&EN_US);
        let ((l, _), (r, _)) = (ci[l_min - 1], ci[s_len - r_min]);
        let within_bounds = |&i| i > l && i <= r;

        TestResult::from_bool(os.iter().all(within_bounds))
    }

    quickcheck(property as fn(String) -> TestResult);
}

#[test]
fn basics() {
    let h1: Standard = "hyphenation".hyphenate(&EN_US);
    let h2: Standard = "project".hyphenate(&EN_US);
    let h3: Standard = "hypha".hyphenate(&EN_US);

    let v1: Vec<&str> = h1.clone().collect();
    let v2: Vec<&str> = h2.clone().collect();
    let v3: Vec<&str> = h3.clone().collect();
    assert_eq!(v1, vec!["hy", "phen", "ation"]);
    assert_eq!(v2, vec!["project"]);
    assert_eq!(v3, vec!["hy", "pha"]);

    let s1: String = h1.punctuate().collect();
    assert_eq!(s1, "hy\u{ad}phen\u{ad}ation".to_owned());
}
<|endoftext|>


<commit_before>extern crate trustines;

mod memory {
    use trustines::memory::Memory;

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.mem[0] = 5;
        m.mem[1] = 10;
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.mem[0] = 2;
        m.mem[1] = 1;
        m.mem[2] = 0;
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    #[test]
    fn absolute() {
    }
    #[test]
    fn absolute_x() {
    }
    #[test]
    fn absolute_y() {
    }
    #[test]
    fn accumulator() {
    }
    #[test]
    fn immediate() {
    }
    #[test]
    fn implied() {
    }
    #[test]
    fn indirect() {
    }
    #[test]
    fn indexed_indirect() {
    }
    #[test]
    fn indirect_indexed() {
    }
    #[test]
    fn relative() {
    }
    #[test]
    fn zeropage() {
    }
    #[test]
    fn zeropage_x() {
    }
    #[test]
    fn zeropage_y() {
    }
}

<commit_msg>more work on address mode stubs<commit_after>extern crate trustines;

mod memory {
    use trustines::memory::Memory;

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.mem[0] = 5;
        m.mem[1] = 10;
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.mem[0] = 2;
        m.mem[1] = 1;
        m.mem[2] = 0;
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }

    #[test]
    fn absolute() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn accumulator() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn immediate() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn implied() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indexed_indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect_indexed() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn relative() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
}

<|endoftext|>


<commit_before>
extern crate fftw;
extern crate num_traits;

use fftw::*;
use num_traits::Zero;

/// Check successive forward and backward transform equals to the identity
#[test]
fn nae_c2c2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan = nae::C2CPlan::new(&[n], &mut a, &mut b, Sign::FFTW_FORWARD, FFTW_MEASURE).unwrap();
    for i in 0..n {
        a[i] = c64::new(1.0, 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    plan.c2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}

/// Check cos transform
#[test]
fn nae_c2c_cos() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan = nae::C2CPlan::new(&[n], &mut a, &mut b, Sign::FFTW_FORWARD, FFTW_MEASURE).unwrap();
    let pi = ::std::f64::consts::PI;
    for i in 0..n {
        a[i] = c64::new((2.0 * pi * i as f64 / n as f64).cos(), 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    for (i, v) in b.iter().enumerate() {
        let ans = if i == 1 || i == n - 1 {
            0.5 * n as f64
        } else {
            0.0
        };
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!(
                "Large difference: v={}, ans={}, dif={}, i={}",
                v,
                ans,
                dif,
                i
            );
        }
    }
}

/// Check successive forward and backward transform equals to the identity
#[test]
fn nae_c2r2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n / 2 + 1];
    let mut b = vec![0.0; n];
    let mut c2r = nae::C2RPlan::new(&[n], &mut a, &mut b, FFTW_MEASURE).unwrap();
    let mut r2c = nae::R2CPlan::new(&[n], &mut b, &mut a, FFTW_MEASURE).unwrap();
    for i in 0..(n / 2 + 1) {
        a[i] = c64::new(1.0, 0.0);
    }
    c2r.c2r(&mut a, &mut b).unwrap();
    r2c.r2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}
<commit_msg>Use new Flag in test<commit_after>
extern crate fftw;
extern crate num_traits;

use fftw::*;
use num_traits::Zero;

/// Check successive forward and backward transform equals to the identity
#[test]
fn nae_c2c2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan = nae::C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::Measure).unwrap();
    for i in 0..n {
        a[i] = c64::new(1.0, 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    plan.c2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}

/// Check cos transform
#[test]
fn nae_c2c_cos() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan = nae::C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::Measure).unwrap();
    let pi = ::std::f64::consts::PI;
    for i in 0..n {
        a[i] = c64::new((2.0 * pi * i as f64 / n as f64).cos(), 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    for (i, v) in b.iter().enumerate() {
        let ans = if i == 1 || i == n - 1 {
            0.5 * n as f64
        } else {
            0.0
        };
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!(
                "Large difference: v={}, ans={}, dif={}, i={}",
                v,
                ans,
                dif,
                i
            );
        }
    }
}

/// Check successive forward and backward transform equals to the identity
#[test]
fn nae_c2r2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n / 2 + 1];
    let mut b = vec![0.0; n];
    let mut c2r = nae::C2RPlan::new(&[n], &mut a, &mut b, Flag::Measure).unwrap();
    let mut r2c = nae::R2CPlan::new(&[n], &mut b, &mut a, Flag::Measure).unwrap();
    for i in 0..(n / 2 + 1) {
        a[i] = c64::new(1.0, 0.0);
    }
    c2r.c2r(&mut a, &mut b).unwrap();
    r2c.r2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}
<|endoftext|>


<commit_before>use super::protos::{Action, ExplanationPoint,ExplanationPoints};
use scaii_core::{ActionWrapper,ReplayAction};
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::error::Error;
use super::ReplayError;
use prost::Message;

pub struct Explanations {
    pub step_indices: Vec<u32>,
    pub expl_map:  BTreeMap<u32, ExplanationPoint>,
}

pub fn is_empty(explanations_option : &Option<Explanations>) -> bool {
    match explanations_option {
        &None => {
            println!("is_empty()? FOUND NONE");
            true
        }
        &Some(ref explanations) => {
            println!("is_empty()? FOUND SOME:{}", explanations.step_indices.len());
            explanations.step_indices.len() == 0
        }
    }
}
pub fn map_explanations(explanation_points: Vec<ExplanationPoint>) -> Result<Option<Explanations>, Box<Error>> {
    println!("MAPPING EXPL POINTS recieved this many {}", explanation_points.len());
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in explanation_points {
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}

pub fn extract_explanations(replay_actions: Vec<ReplayAction>, r_actions_sans_explanations: &mut Vec<ReplayAction>) -> Result<Vec<ExplanationPoint>, Box<Error>> {
    let mut explanation_points: Vec<ExplanationPoint> = Vec::new();
    for replay_action in replay_actions {
        match replay_action {
            ReplayAction::Delta(action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Delta(new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Keyframe(ser_info, action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Keyframe(ser_info, new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Header(_) => {
                r_actions_sans_explanations.push(replay_action);
            },
        }
    }
    Ok(explanation_points)
}

fn get_serialized_action(action: &Action) -> Result<Vec<u8>, Box<Error>> {
    let mut action_data: Vec<u8> = Vec::new();
    action.encode(&mut action_data)?;
    Ok(action_data)
}

fn extract_explanation_from_action_wrapper(action_wrapper : ActionWrapper, explanation_points : &mut Vec<ExplanationPoint>) -> Result<ActionWrapper, Box<Error>> {
    let data = action_wrapper.serialized_action;
    let action_decode_result = Action::decode(data);
    match action_decode_result {
        Ok(action) =>  {
            match action.explanation {
                None => {
                    println!("Explanation?  None");
                },
                Some(explanation_point) => {
                    println!("Explanation?  YES");
                    explanation_points.push(explanation_point);
                },
            }
            // make new Action without Explanation
            let new_action = Action{
                discrete_actions : action.discrete_actions,
                continuous_actions : action.continuous_actions,
                alternate_actions : action.alternate_actions,
                explanation : Option::None,
            };
            let mut new_action_data: Vec<u8> = Vec::new();
            new_action.encode(&mut new_action_data)?;
            Ok(ActionWrapper {
                has_explanation: false,
                step: action_wrapper.step,
                title: action_wrapper.title,
                serialized_action: new_action_data,
            })
        }
        Err(err) => {
            Err(Box::new(ReplayError::new("could not decode ActionWrapper during explanation stripping")))
        }
    }
}

pub fn get_explanations_for_replay_file(mut path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    let path_clone = path.clone();
    let filestem_option = path_clone.file_stem();
    match filestem_option {
        Some(os_stem_string) => {
            println!("os_stem_string is {:?}", os_stem_string);
            let filestem: String = os_stem_string.to_str().unwrap().to_string();
            let explanation_filename = format!("{}.exp", filestem);
            path.pop(); // parent dir
            path.push(explanation_filename);
            println!("explanation filepath is {:?}", path);
            get_explanations_for_explanations_file(path)
        },
        None => Ok(None)
    }
}

pub fn get_explanations_for_explanations_file(path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    use std::fs::File;
    use std::io::BufReader;
    use std::io::Read;
    use super::prost::Message;

    if !path.as_path().exists() {
        return Ok(None);
    }
    let replay_file = File::open(path.clone()).expect("file not found");
    let mut bytes : Vec<u8> = Vec::new();
    let mut reader = BufReader::new(replay_file);
    let read_result = reader.read_to_end(&mut bytes);
    match read_result {
        Ok(read_usize) => {
            println!("read this many bytes {:?}", read_usize);
            let explanation_points =
                ExplanationPoints::decode(bytes)?;
           // assert!(explanation_points.explanation_points.len() == 3);
            println!("explanation point count {}", explanation_points.explanation_points.len());
            let explanations_option = get_explanations_for_explanation_points(explanation_points)?;
            Ok(explanations_option)
        },
        Err(err) => {
            return Err(Box::new(ReplayError::new(&format!("ERROR - failed to read explanations file {:?}", path))));
        },
    }
}

fn get_explanations_for_explanation_points(expl_points : ExplanationPoints) -> Result<Option<Explanations>, Box<Error>> {
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in expl_points.explanation_points{
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}<commit_msg>better error message<commit_after>use super::protos::{Action, ExplanationPoint,ExplanationPoints};
use scaii_core::{ActionWrapper,ReplayAction};
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::error::Error;
use super::ReplayError;
use prost::Message;

pub struct Explanations {
    pub step_indices: Vec<u32>,
    pub expl_map:  BTreeMap<u32, ExplanationPoint>,
}

pub fn is_empty(explanations_option : &Option<Explanations>) -> bool {
    match explanations_option {
        &None => {
            println!("is_empty()? FOUND NONE");
            true
        }
        &Some(ref explanations) => {
            println!("is_empty()? FOUND SOME:{}", explanations.step_indices.len());
            explanations.step_indices.len() == 0
        }
    }
}
pub fn map_explanations(explanation_points: Vec<ExplanationPoint>) -> Result<Option<Explanations>, Box<Error>> {
    println!("MAPPING EXPL POINTS recieved this many {}", explanation_points.len());
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in explanation_points {
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}

pub fn extract_explanations(replay_actions: Vec<ReplayAction>, r_actions_sans_explanations: &mut Vec<ReplayAction>) -> Result<Vec<ExplanationPoint>, Box<Error>> {
    let mut explanation_points: Vec<ExplanationPoint> = Vec::new();
    for replay_action in replay_actions {
        match replay_action {
            ReplayAction::Delta(action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Delta(new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Keyframe(ser_info, action_wrapper) => {
                let new_action_wrapper = extract_explanation_from_action_wrapper(action_wrapper, &mut explanation_points)?;
                let new_replay_action = ReplayAction::Keyframe(ser_info, new_action_wrapper);
                r_actions_sans_explanations.push(new_replay_action);
            }
            ReplayAction::Header(_) => {
                r_actions_sans_explanations.push(replay_action);
            },
        }
    }
    Ok(explanation_points)
}

fn get_serialized_action(action: &Action) -> Result<Vec<u8>, Box<Error>> {
    let mut action_data: Vec<u8> = Vec::new();
    action.encode(&mut action_data)?;
    Ok(action_data)
}

fn extract_explanation_from_action_wrapper(action_wrapper : ActionWrapper, explanation_points : &mut Vec<ExplanationPoint>) -> Result<ActionWrapper, Box<Error>> {
    let data = action_wrapper.serialized_action;
    let action_decode_result = Action::decode(data);
    match action_decode_result {
        Ok(action) =>  {
            println!("ACTION DECODED AS {:?}", action);
            match action.explanation {
                None => {
                    println!("Explanation?  None");
                },
                Some(explanation_point) => {
                    println!("Explanation?  YES");
                    explanation_points.push(explanation_point);
                },
            }
            // make new Action without Explanation
            let new_action = Action{
                discrete_actions : action.discrete_actions,
                continuous_actions : action.continuous_actions,
                alternate_actions : action.alternate_actions,
                explanation : Option::None,
            };
            let mut new_action_data: Vec<u8> = Vec::new();
            new_action.encode(&mut new_action_data)?;
            Ok(ActionWrapper {
                has_explanation: false,
                step: action_wrapper.step,
                title: action_wrapper.title,
                serialized_action: new_action_data,
            })
        }
        Err(err) => {
            Err(Box::new(ReplayError::new("could not decode ActionWrapper during explanation stripping")))
        }
    }
}

pub fn get_explanations_for_replay_file(mut path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    let path_clone = path.clone();
    let filestem_option = path_clone.file_stem();
    match filestem_option {
        Some(os_stem_string) => {
            println!("os_stem_string is {:?}", os_stem_string);
            let filestem: String = os_stem_string.to_str().unwrap().to_string();
            let explanation_filename = format!("{}.exp", filestem);
            path.pop(); // parent dir
            path.push(explanation_filename);
            println!("explanation filepath is {:?}", path);
            get_explanations_for_explanations_file(path)
        },
        None => Ok(None)
    }
}

pub fn get_explanations_for_explanations_file(path: PathBuf) -> Result<Option<Explanations>, Box<Error>> {
    use std::fs::File;
    use std::io::BufReader;
    use std::io::Read;
    use super::prost::Message;

    if !path.as_path().exists() {
        return Ok(None);
    }
    let replay_file = File::open(path.clone()).expect("file not found");
    let mut bytes : Vec<u8> = Vec::new();
    let mut reader = BufReader::new(replay_file);
    let read_result = reader.read_to_end(&mut bytes);
    match read_result {
        Ok(read_usize) => {
            println!("read this many bytes {:?}", read_usize);
            let explanation_points =
                ExplanationPoints::decode(bytes)?;
           // assert!(explanation_points.explanation_points.len() == 3);
            println!("explanation point count {}", explanation_points.explanation_points.len());
            let explanations_option = get_explanations_for_explanation_points(explanation_points)?;
            Ok(explanations_option)
        },
        Err(err) => {
            return Err(Box::new(ReplayError::new(&format!("ERROR - failed to read explanations file {:?} - {:?}", path, err.description()))));
        },
    }
}

fn get_explanations_for_explanation_points(expl_points : ExplanationPoints) -> Result<Option<Explanations>, Box<Error>> {
    let mut step_indices : Vec<u32> = Vec::new();
    let mut expl_map: BTreeMap<u32, ExplanationPoint> = BTreeMap::new();
    for expl_point in expl_points.explanation_points{
        let step = expl_point.step.unwrap();
        step_indices.push(step.clone());
        expl_map.insert(step,expl_point.clone());
    }
    Ok(Some(Explanations {
        step_indices: step_indices,
        expl_map: expl_map,
    }))
}<|endoftext|>


<commit_before>use reqwest;
pub use reqwest::header::ContentType;
use reqwest::Response;
pub use reqwest::{Method, StatusCode};
use result::{MwsError, MwsResult};
use sign::SignatureV2;
use std::io::Read;
use xmlhelper::decode::{FromXmlStream, Stream};
use SerializeMwsParams;

#[derive(Debug)]
pub struct ErrorResponse {
  pub status: StatusCode,
  pub info: Option<ErrorResponseInfo>,
  pub raw: String,
}

#[derive(Debug, Default)]
pub struct ErrorResponseInfo {
  pub errors: Vec<ErrorResponseError>,
  pub request_id: String,
}

#[derive(Debug, Default, PartialEq)]
pub struct ErrorResponseError {
  pub error_type: String,
  pub code: String,
  pub message: String,
  pub detail: String,
}

impl ErrorResponseInfo {
  fn from_xml_stream<R: ::std::io::Read>(s: &mut Stream<R>) -> MwsResult<ErrorResponseInfo> {
    use xmlhelper::decode::{characters, element, fold_elements, start_document};
    start_document(s)?;
    element(s, "ErrorResponse", |s| {
      fold_elements(s, ErrorResponseInfo::default(), |s, resp| {
        match s.local_name() {
          "Error" => {
            let err = fold_elements(s, ErrorResponseError::default(), |s, err| {
              match s.local_name() {
                "Type" => {
                  err.error_type = characters(s)?;
                }
                "Code" => {
                  err.code = characters(s)?;
                }
                "Message" => {
                  err.message = characters(s)?;
                }
                "Detail" => {
                  err.detail = characters(s)?;
                }
                _ => {}
              }
              Ok(())
            })?;
            resp.errors.push(err);
          }
          "RequestID" => {
            resp.request_id = characters(s)?;
          }
          _ => {}
        }
        Ok(())
      })
    })
    .into()
  }
}

impl FromXmlStream<Stream<reqwest::Response>> for ErrorResponseInfo {
  fn from_xml(s: &mut Stream<reqwest::Response>) -> MwsResult<ErrorResponseInfo> {
    ErrorResponseInfo::from_xml_stream(s)
  }
}

impl FromXmlStream<Stream<::std::io::Cursor<String>>> for ErrorResponseInfo {
  fn from_xml(s: &mut Stream<::std::io::Cursor<String>>) -> MwsResult<ErrorResponseInfo> {
    ErrorResponseInfo::from_xml_stream(s)
  }
}

/// [Reference](http://docs.developer.amazonservices.com/en_CA/dev_guide/DG_Endpoints.html)
pub struct ClientOptions {
  /// Your software can access Amazon Marketplace Web Service (Amazon MWS) using region-specific endpoints.
  pub endpoint: String,

  /// Your seller or merchant identifier.
  pub seller_id: String,

  /// Represents the authorization of a specific developer of a web application by a specific Amazon seller.
  pub mws_auth_token: Option<String>,

  /// Your Amazon MWS account is identified by your access key Id, which Amazon MWS uses to look up your Secret Access Key.
  pub aws_access_key_id: String,
  pub secret_key: String,
}

pub struct Client {
  options: ClientOptions,
  http_client: reqwest::Client,
}

impl Client {
  pub fn new(options: ClientOptions) -> MwsResult<Client> {
    Ok(Client {
      options: options,
      http_client: reqwest::Client::new(),
    })
  }

  pub fn with_http_client(options: ClientOptions, http_client: reqwest::Client) -> Client {
    Client {
      options: options,
      http_client: http_client,
    }
  }

  pub fn request<P>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<reqwest::Response>
  where
    P: SerializeMwsParams,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    sign.add("SellerId", &self.options.seller_id);
    //sign.add("Merchant", self.options.seller_id.as_ref());
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    //println!("request: {}", url);
    self
      .http_client
      .request(method, &url)
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)
  }

  pub fn request_with_body<P, R>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
    body: R,
    content_md5: String,
    content_type: ContentType,
  ) -> MwsResult<reqwest::Response>
  where
    P: SerializeMwsParams,
    R: Read + Send + 'static,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    sign.add("SellerId", &self.options.seller_id);
    sign.add("ContentMD5Value", content_md5);
    //sign.add("Merchant", self.options.seller_id.as_ref());
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    //println!("request: {}", url);

    self
      .http_client
      .request(method, &url)
      .header(content_type)
      .body(reqwest::Body::new(body))
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)
  }

  pub fn request_xml<P, T>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<T>
  where
    P: SerializeMwsParams,
    T: FromXmlStream<Stream<reqwest::Response>>,
  {
    let resp = self.request(method, path, version, action, parameters)?;
    let mut stream = Stream::new(resp);
    let v = T::from_xml(&mut stream)?;
    Ok(v)
  }

  pub fn request_xml_with_body<P, R, T>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
    body: R,
    content_md5: String,
    content_type: ContentType,
  ) -> MwsResult<T>
  where
    P: SerializeMwsParams,
    T: FromXmlStream<Stream<reqwest::Response>>,
    R: Read + Send + 'static,
  {
    let resp = self.request_with_body(
      method,
      path,
      version,
      action,
      parameters,
      body,
      content_md5,
      content_type,
    )?;
    let mut stream = Stream::new(resp);
    let v = T::from_xml(&mut stream)?;
    Ok(v)
  }

  pub fn request_raw<P>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<(StatusCode, String)>
  where
    P: SerializeMwsParams,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    let mut resp = self
      .http_client
      .request(method, &url)
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)?;
    let mut s = String::new();
    resp.read_to_string(&mut s)?;
    Ok((resp.status().clone(), s))
  }
}

fn handle_error_status(resp: Response) -> MwsResult<Response> {
  if resp.status().is_success() {
    Ok(resp)
  } else {
    use std::io::Cursor;

    let mut resp = resp;
    let mut body = String::new();
    resp.read_to_string(&mut body)?;
    let mut s = Stream::new(Cursor::new(body.clone()));
    match ErrorResponseInfo::from_xml(&mut s) {
      Ok(info) => Err(MwsError::ErrorResponse(ErrorResponse {
        status: resp.status().clone(),
        raw: body,
        info: Some(info),
      })),
      Err(_) => Err(MwsError::ErrorResponse(ErrorResponse {
        status: resp.status().clone(),
        raw: body,
        info: None,
      })),
    }
  }
}

#[cfg(test)]
pub fn get_test_client() -> Client {
  use std::env;
  Client::new(ClientOptions {
    endpoint: env::var("Endpoint").expect("get Endpoint"),
    seller_id: env::var("SellerId").expect("get SellerId"),
    mws_auth_token: None,
    aws_access_key_id: env::var("AWSAccessKeyId").expect("get AWSAccessKeyId"),
    secret_key: env::var("SecretKey").expect("get SecretKey"),
  })
  .expect("create client")
}

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

  #[test]
  #[ignore]
  fn it_works() {
    dotenv().ok();
    let client = get_test_client();
    let (status, body) = client
      .request_raw(
        Method::Post,
        "/Orders/2013-09-01",
        "2013-09-01",
        "GetServiceStatus",
        (),
      )
      .expect("send request");
    assert!(status.is_success());
    assert!(body.starts_with("<?xml"));

    use std::io::Cursor;
    let (status, body) = client
      .request_raw(
        Method::Post,
        "/Fake/2013-09-01",
        "2013-09-01",
        "GetServiceStatus",
        (),
      )
      .expect("send request");
    assert!(!status.is_success());
    let source = Cursor::new(body);
    let mut s = Stream::new(source);
    let err_info = ErrorResponseInfo::from_xml(&mut s).expect("decode error response");
    assert_eq!(err_info.errors.len(), 1);
    assert_eq!(
      err_info.errors[0],
      ErrorResponseError {
        error_type: "Sender".to_string(),
        code: "InvalidAddress".to_string(),
        message: "Section Fake/2013-09-01 is invalid".to_string(),
        detail: "".to_string(),
      }
    );
  }
}
<commit_msg>refactor: `request_raw` returns headers and raw bytes.<commit_after>use reqwest;
pub use reqwest::header::ContentType;
use reqwest::Response;
pub use reqwest::{Method, StatusCode};
use result::{MwsError, MwsResult};
use sign::SignatureV2;
use std::io::Read;
use xmlhelper::decode::{FromXmlStream, Stream};
use SerializeMwsParams;

#[derive(Debug)]
pub struct ErrorResponse {
  pub status: StatusCode,
  pub info: Option<ErrorResponseInfo>,
  pub raw: String,
}

#[derive(Debug, Default)]
pub struct ErrorResponseInfo {
  pub errors: Vec<ErrorResponseError>,
  pub request_id: String,
}

#[derive(Debug, Default, PartialEq)]
pub struct ErrorResponseError {
  pub error_type: String,
  pub code: String,
  pub message: String,
  pub detail: String,
}

impl ErrorResponseInfo {
  fn from_xml_stream<R: ::std::io::Read>(s: &mut Stream<R>) -> MwsResult<ErrorResponseInfo> {
    use xmlhelper::decode::{characters, element, fold_elements, start_document};
    start_document(s)?;
    element(s, "ErrorResponse", |s| {
      fold_elements(s, ErrorResponseInfo::default(), |s, resp| {
        match s.local_name() {
          "Error" => {
            let err = fold_elements(s, ErrorResponseError::default(), |s, err| {
              match s.local_name() {
                "Type" => {
                  err.error_type = characters(s)?;
                }
                "Code" => {
                  err.code = characters(s)?;
                }
                "Message" => {
                  err.message = characters(s)?;
                }
                "Detail" => {
                  err.detail = characters(s)?;
                }
                _ => {}
              }
              Ok(())
            })?;
            resp.errors.push(err);
          }
          "RequestID" => {
            resp.request_id = characters(s)?;
          }
          _ => {}
        }
        Ok(())
      })
    })
    .into()
  }
}

impl FromXmlStream<Stream<reqwest::Response>> for ErrorResponseInfo {
  fn from_xml(s: &mut Stream<reqwest::Response>) -> MwsResult<ErrorResponseInfo> {
    ErrorResponseInfo::from_xml_stream(s)
  }
}

impl FromXmlStream<Stream<::std::io::Cursor<String>>> for ErrorResponseInfo {
  fn from_xml(s: &mut Stream<::std::io::Cursor<String>>) -> MwsResult<ErrorResponseInfo> {
    ErrorResponseInfo::from_xml_stream(s)
  }
}

/// [Reference](http://docs.developer.amazonservices.com/en_CA/dev_guide/DG_Endpoints.html)
pub struct ClientOptions {
  /// Your software can access Amazon Marketplace Web Service (Amazon MWS) using region-specific endpoints.
  pub endpoint: String,

  /// Your seller or merchant identifier.
  pub seller_id: String,

  /// Represents the authorization of a specific developer of a web application by a specific Amazon seller.
  pub mws_auth_token: Option<String>,

  /// Your Amazon MWS account is identified by your access key Id, which Amazon MWS uses to look up your Secret Access Key.
  pub aws_access_key_id: String,
  pub secret_key: String,
}

pub struct Client {
  options: ClientOptions,
  http_client: reqwest::Client,
}

impl Client {
  pub fn new(options: ClientOptions) -> MwsResult<Client> {
    Ok(Client {
      options: options,
      http_client: reqwest::Client::new(),
    })
  }

  pub fn with_http_client(options: ClientOptions, http_client: reqwest::Client) -> Client {
    Client {
      options: options,
      http_client: http_client,
    }
  }

  pub fn request<P>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<reqwest::Response>
  where
    P: SerializeMwsParams,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    sign.add("SellerId", &self.options.seller_id);
    //sign.add("Merchant", self.options.seller_id.as_ref());
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    //println!("request: {}", url);
    self
      .http_client
      .request(method, &url)
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)
  }

  pub fn request_with_body<P, R>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
    body: R,
    content_md5: String,
    content_type: ContentType,
  ) -> MwsResult<reqwest::Response>
  where
    P: SerializeMwsParams,
    R: Read + Send + 'static,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    sign.add("SellerId", &self.options.seller_id);
    sign.add("ContentMD5Value", content_md5);
    //sign.add("Merchant", self.options.seller_id.as_ref());
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    //println!("request: {}", url);

    self
      .http_client
      .request(method, &url)
      .header(content_type)
      .body(reqwest::Body::new(body))
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)
  }

  pub fn request_xml<P, T>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<T>
  where
    P: SerializeMwsParams,
    T: FromXmlStream<Stream<reqwest::Response>>,
  {
    let resp = self.request(method, path, version, action, parameters)?;
    let mut stream = Stream::new(resp);
    let v = T::from_xml(&mut stream)?;
    Ok(v)
  }

  pub fn request_xml_with_body<P, R, T>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
    body: R,
    content_md5: String,
    content_type: ContentType,
  ) -> MwsResult<T>
  where
    P: SerializeMwsParams,
    T: FromXmlStream<Stream<reqwest::Response>>,
    R: Read + Send + 'static,
  {
    let resp = self.request_with_body(
      method,
      path,
      version,
      action,
      parameters,
      body,
      content_md5,
      content_type,
    )?;
    let mut stream = Stream::new(resp);
    let v = T::from_xml(&mut stream)?;
    Ok(v)
  }

  pub fn request_raw<P>(
    &self,
    method: Method,
    path: &str,
    version: &str,
    action: &str,
    parameters: P,
  ) -> MwsResult<(StatusCode, Vec<(String, String)>, Vec<u8>)>
  where
    P: SerializeMwsParams,
  {
    let mut sign = SignatureV2::new(
      &self.options.endpoint,
      &self.options.aws_access_key_id,
      &self.options.secret_key,
      self.options.mws_auth_token.as_ref().map(AsRef::as_ref),
    );
    for (k, v) in parameters.into_mws_params() {
      sign.add(&k, v);
    }
    let url = sign
      .generate_url(method.clone(), path, version, action)?
      .to_string();
    let mut resp = self
      .http_client
      .request(method, &url)
      .send()
      .map_err(MwsError::from)
      .and_then(handle_error_status)?;

    let headers = resp
      .headers()
      .iter()
      .map(|view| (view.name().to_string(), view.value_string()))
      .collect();

    let mut body = vec![];
    resp.read_to_end(&mut body)?;
    Ok((resp.status().clone(), headers, body))
  }
}

fn handle_error_status(resp: Response) -> MwsResult<Response> {
  if resp.status().is_success() {
    Ok(resp)
  } else {
    use std::io::Cursor;

    let mut resp = resp;
    let mut body = String::new();
    resp.read_to_string(&mut body)?;
    let mut s = Stream::new(Cursor::new(body.clone()));
    match ErrorResponseInfo::from_xml(&mut s) {
      Ok(info) => Err(MwsError::ErrorResponse(ErrorResponse {
        status: resp.status().clone(),
        raw: body,
        info: Some(info),
      })),
      Err(_) => Err(MwsError::ErrorResponse(ErrorResponse {
        status: resp.status().clone(),
        raw: body,
        info: None,
      })),
    }
  }
}

#[cfg(test)]
pub fn get_test_client() -> Client {
  use std::env;
  Client::new(ClientOptions {
    endpoint: env::var("Endpoint").expect("get Endpoint"),
    seller_id: env::var("SellerId").expect("get SellerId"),
    mws_auth_token: None,
    aws_access_key_id: env::var("AWSAccessKeyId").expect("get AWSAccessKeyId"),
    secret_key: env::var("SecretKey").expect("get SecretKey"),
  })
  .expect("create client")
}

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

  #[test]
  #[ignore]
  fn it_works() {
    dotenv().ok();
    let client = get_test_client();
    let (status, _, body) = client
      .request_raw(
        Method::Post,
        "/Orders/2013-09-01",
        "2013-09-01",
        "GetServiceStatus",
        (),
      )
      .expect("send request");
    let body = String::from_utf8(body).unwrap();
    assert!(status.is_success());
    assert!(body.starts_with("<?xml"));

    use std::io::Cursor;
    let (status, _, body) = client
      .request_raw(
        Method::Post,
        "/Fake/2013-09-01",
        "2013-09-01",
        "GetServiceStatus",
        (),
      )
      .expect("send request");
    let body = String::from_utf8(body).unwrap();
    assert!(!status.is_success());
    let source = Cursor::new(body);
    let mut s = Stream::new(source);
    let err_info = ErrorResponseInfo::from_xml(&mut s).expect("decode error response");
    assert_eq!(err_info.errors.len(), 1);
    assert_eq!(
      err_info.errors[0],
      ErrorResponseError {
        error_type: "Sender".to_string(),
        code: "InvalidAddress".to_string(),
        message: "Section Fake/2013-09-01 is invalid".to_string(),
        detail: "".to_string(),
      }
    );
  }
}
<|endoftext|>


<commit_before>pub mod ui;
use core::geometry::CPath;
use kay::{ID, CVec, CDict, Recipient, World, ActorSystem, InMemory, Compact};
use compass::{FiniteCurve, Path, Segment, P2, V2};
use core::simulation::{Simulation, Tick, AddSimulatable};
use ordered_float::OrderedFloat;
use ::std::f32::INFINITY;
use ::std::ops::{Deref, DerefMut};

#[derive(Copy, Clone)]
struct Obstacle {
    position: OrderedFloat<f32>,
    velocity: f32
}

impl Obstacle {
    fn far_away() -> Obstacle {Obstacle{position: OrderedFloat(INFINITY), velocity: INFINITY}}
}

#[derive(Copy, Clone)]
struct LaneCar {
    trip: ID,
    as_obstacle: Obstacle,
    acceleration: f32,
    max_velocity: f32
}

impl Deref for LaneCar {
    type Target = Obstacle;

    fn deref(&self) -> &Obstacle {&self.as_obstacle}
}

impl DerefMut for LaneCar {
    fn deref_mut(&mut self) -> &mut Obstacle {&mut self.as_obstacle}
}

#[derive(Copy, Clone)]
struct ParallelOverlap {
    partner_lane: ID,
    start: OrderedFloat<f32>,
    end: OrderedFloat<f32>,
    partner_start: OrderedFloat<f32>,
    partner_end: OrderedFloat<f32>
}

derive_compact!{
    pub struct Lane {
        length: f32,
        path: CPath,
        next_lanes_with_obstacles: CDict<ID, Obstacle>,
        previous_lanes: CVec<ID>,
        overlaps: CVec<ParallelOverlap>,
        overlap_obstacles: CVec<Obstacle>,
        cars: CVec<LaneCar>
    }
}

impl Lane {
    fn new(path: CPath, next_lane: Option<ID>, previous_lane: Option<ID>) -> Self {
        let length = path.length();
        let mut next_lanes_with_obstacles = CDict::new();
        let mut previous_lanes = CVec::new();
        if let Some(id) = next_lane {next_lanes_with_obstacles.insert(id, Obstacle::far_away());}
        if let Some(id) = previous_lane {previous_lanes.push(id);}
        Lane {
            length: length,
            path: path,
            next_lanes_with_obstacles: next_lanes_with_obstacles,
            previous_lanes: previous_lanes,
            overlaps: CVec::new(),
            overlap_obstacles: CVec::new(),
            cars: CVec::new()
        }
    }

    fn add_next_lane(&mut self, next_lane: ID) {
        self.next_lanes_with_obstacles.insert(next_lane, Obstacle::far_away());
    }
}

#[derive(Copy, Clone)]
struct AddCar(LaneCar);

#[derive(Copy, Clone)]
struct UpdateObstacleOnNextLane(ID, Obstacle);

#[derive(Copy, Clone)]
struct AddOverlapObstacle(Obstacle);

recipient!(Lane, (&mut self, world: &mut World, self_id: ID) {
    AddCar: &AddCar(car) => {
        self.cars.insert(0, car);
    },

    Tick: &Tick{dt} => {
        let first_obstacle_on_any_next_lane = self.next_lanes_with_obstacles.pairs.iter()
            .min_by_key(|&&(_id, first_obstacle)| {first_obstacle.position})
            .map_or(Obstacle::far_away(), |&(_id, first_obstacle)| {Obstacle{
                position: OrderedFloat(*first_obstacle.position + self.length),
                velocity: first_obstacle.velocity
            }});

        if self.cars.len() >= 2 {
            for c in 0..self.cars.len() {
                let next_car = if c + 1 < self.cars.len() {*self.cars[c + 1]} else {first_obstacle_on_any_next_lane};
                let car = &mut self.cars[c];
                let next_car_acceleration = intelligent_driver_acceleration(car, &next_car);

                // TODO: optimize, avoid nested loop
                let next_overlap_obstacle = self.overlap_obstacles.iter().find(|obstacle| obstacle.position > car.position);
                let next_overlap_obstacle_acceleration = match next_overlap_obstacle {
                    Some(obstacle) => intelligent_driver_acceleration(car, obstacle),
                    None => INFINITY
                };

                car.acceleration = next_car_acceleration.min(next_overlap_obstacle_acceleration);
            }
        }

        for car in &mut self.cars {
            *car.position += dt * car.velocity;
            car.velocity = car.max_velocity.min(car.velocity + dt * car.acceleration).max(0.0);
        }

        while self.cars.len() > 0 {
            let mut last_car = self.cars[self.cars.len() - 1];
            if *last_car.position > self.length {
                *last_car.position -= self.length;
                if let Some(next_lane) = self.next_lanes_with_obstacles.keys().next() {
                    world.send(next_lane, AddCar(last_car));
                }
                self.cars.pop();
            } else {break;}
        }

        let first_obstacle = match &self.cars.first() {
            &Some(ref car) => *car,
            &None => &first_obstacle_on_any_next_lane
        };
        for previous_lane in self.previous_lanes.iter() {
            world.send(*previous_lane, UpdateObstacleOnNextLane(self_id, *first_obstacle));
        }

        for overlap in self.overlaps.iter() {
            for car in self.cars.iter().filter(|car| car.position > overlap.start && car.position < overlap.end) {
                world.send(overlap.partner_lane, AddOverlapObstacle(Obstacle{
                    position: OrderedFloat(*car.position - *overlap.start + *overlap.partner_start),
                    velocity: car.velocity
                }));
            }
        }

        self.overlap_obstacles.clear();
    },

    UpdateObstacleOnNextLane: &UpdateObstacleOnNextLane(next_lane_id, first_obstacle) => {
        self.next_lanes_with_obstacles.insert(next_lane_id, first_obstacle);
    },

    AddOverlapObstacle: &AddOverlapObstacle(obstacle) => {
        self.overlap_obstacles.push(obstacle);
    }
});

fn intelligent_driver_acceleration(car: &LaneCar, obstacle: &Obstacle) -> f32 {
    // http://en.wikipedia.org/wiki/Intelligent_driver_model

    let car_length = 4.0;
    let acceleration = 5.0;
	let comfortable_breaking_deceleration : f32 = 4.0;
	let max_deceleration : f32 = 14.0;
	let desired_velocity = car.max_velocity;
	let safe_time_headway = 1.0;
	let acceleration_exponent = 4.0;
	let minimum_spacing = 10.0;

	let net_distance = *obstacle.position - *car.position - car_length;
	let velocity_difference = car.velocity - obstacle.velocity;

	let s_star = minimum_spacing + 0.0f32.max(car.velocity * safe_time_headway
		+ (car.velocity * velocity_difference / (2.0 * (acceleration * comfortable_breaking_deceleration).sqrt())));

    let result_acceleration = (-max_deceleration).max(acceleration * (
		1.0
		- (car.velocity / desired_velocity).powf(acceleration_exponent)
		- (s_star / net_distance).powf(2.0)
	));

	result_acceleration
}

pub fn setup(system: &mut ActorSystem) {
    system.add_swarm::<Lane>(InMemory("lane_actors", 512 * 64, 10));
    system.add_inbox::<AddCar, Lane>(InMemory("add_car", 512, 4));
    system.add_inbox::<UpdateObstacleOnNextLane, Lane>(InMemory("update_obstacle_on_next_lane", 512, 4));
    system.add_inbox::<AddOverlapObstacle, Lane>(InMemory("add_overlap_obstacle", 512, 4));
    system.add_inbox::<Tick, Lane>(InMemory("tick", 512, 4));

    system.world().send_to_individual::<_, Simulation>(AddSimulatable(system.broadcast_id::<Lane>()));

    setup_scenario(system);
}

fn setup_scenario(system: &mut ActorSystem) {
    let mut world = system.world();

    let mut lane1 = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(0.0, 0.0), P2::new(300.0, 0.0)),
            Segment::arc_with_direction(P2::new(300.0, 0.0), V2::new(1.0, 0.0), P2::new(300.0, 100.0))
        ]),
        None,
        None
    ));

    let mut lane3 = world.create(Lane::new(
        CPath::new(vec![
            Segment::arc_with_direction(P2::new(0.0, 100.0), V2::new(-1.0, 0.0), P2::new(0.0, 0.0))
        ]),
        Some(lane1.id),
        None
    ));

    let lane2 = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(300.0, 100.0), P2::new(0.0, 100.0))
        ]),
        Some(lane3.id),
        Some(lane1.id)
    ));

    let mut overlapping_lane = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(0.0, -10.0), P2::new(300.0, 10.0))
        ]),
        None,
        None
    ));

    lane1.add_next_lane(lane2.id);
    lane1.previous_lanes.push(lane3.id);
    lane3.previous_lanes.push(lane2.id);

    lane1.overlaps.push(ParallelOverlap{
        partner_lane: overlapping_lane.id,
        start: OrderedFloat(100.0),
        end: OrderedFloat(200.0),
        partner_start: OrderedFloat(100.0),
        partner_end: OrderedFloat(200.0),
    });

    overlapping_lane.overlaps.push(ParallelOverlap{
        partner_lane: lane1.id,
        start: OrderedFloat(100.0),
        end: OrderedFloat(200.0),
        partner_start: OrderedFloat(100.0),
        partner_end: OrderedFloat(200.0),
    });

    let lane1_id = lane1.id;
    let lane2_id = lane2.id;
    let overlapping_lane_id = overlapping_lane.id;

    world.start(lane1);
    world.start(lane2);
    world.start(lane3);
    world.start(overlapping_lane);

    let n_cars = 10;
    for i in 0..n_cars {
        world.send(lane1_id, AddCar(LaneCar{
            as_obstacle: Obstacle {
                position: OrderedFloat(n_cars as f32 * 5.0 - (i as f32 * 5.0)),
                velocity: 0.0,
            },
            trip: ID::invalid(),
            acceleration: 1.0,
            max_velocity: 22.0
        }));
    }

    world.send(lane2_id, AddCar(LaneCar{
        as_obstacle: Obstacle {
            position: OrderedFloat(5.0),
            velocity: 0.0,
        },
        trip: ID::invalid(),
        acceleration: 1.0,
        max_velocity: 0.0
    }));

    world.send(overlapping_lane_id, AddCar(LaneCar{
        as_obstacle: Obstacle {
            position: OrderedFloat(80.0),
            velocity: 0.0,
        },
        trip: ID::invalid(),
        acceleration: 1.0,
        max_velocity: 10.0
    }));
}<commit_msg>Cars break for cars on conflicting/oncoming overlaps #10<commit_after>pub mod ui;
use core::geometry::CPath;
use kay::{ID, CVec, CDict, Recipient, World, ActorSystem, InMemory, Compact};
use compass::{FiniteCurve, Path, Segment, P2, V2};
use core::simulation::{Simulation, Tick, AddSimulatable};
use ordered_float::OrderedFloat;
use ::std::f32::INFINITY;
use ::std::ops::{Deref, DerefMut};

#[derive(Copy, Clone)]
struct Obstacle {
    position: OrderedFloat<f32>,
    velocity: f32
}

impl Obstacle {
    fn far_away() -> Obstacle {Obstacle{position: OrderedFloat(INFINITY), velocity: INFINITY}}
}

#[derive(Copy, Clone)]
struct LaneCar {
    trip: ID,
    as_obstacle: Obstacle,
    acceleration: f32,
    max_velocity: f32
}

impl Deref for LaneCar {
    type Target = Obstacle;

    fn deref(&self) -> &Obstacle {&self.as_obstacle}
}

impl DerefMut for LaneCar {
    fn deref_mut(&mut self) -> &mut Obstacle {&mut self.as_obstacle}
}

#[derive(Copy, Clone)]
enum OverlapKind{Parallel, Conflicting}
use self::OverlapKind::{Parallel, Conflicting};

#[derive(Copy, Clone)]
struct Overlap {
    partner_lane: ID,
    start: OrderedFloat<f32>,
    end: OrderedFloat<f32>,
    partner_start: OrderedFloat<f32>,
    partner_end: OrderedFloat<f32>,
    kind: OverlapKind
}

derive_compact!{
    pub struct Lane {
        length: f32,
        path: CPath,
        next_lanes_with_obstacles: CDict<ID, Obstacle>,
        previous_lanes: CVec<ID>,
        overlaps: CVec<Overlap>,
        overlap_obstacles: CVec<Obstacle>,
        cars: CVec<LaneCar>
    }
}

impl Lane {
    fn new(path: CPath, next_lane: Option<ID>, previous_lane: Option<ID>) -> Self {
        let length = path.length();
        let mut next_lanes_with_obstacles = CDict::new();
        let mut previous_lanes = CVec::new();
        if let Some(id) = next_lane {next_lanes_with_obstacles.insert(id, Obstacle::far_away());}
        if let Some(id) = previous_lane {previous_lanes.push(id);}
        Lane {
            length: length,
            path: path,
            next_lanes_with_obstacles: next_lanes_with_obstacles,
            previous_lanes: previous_lanes,
            overlaps: CVec::new(),
            overlap_obstacles: CVec::new(),
            cars: CVec::new()
        }
    }

    fn add_next_lane(&mut self, next_lane: ID) {
        self.next_lanes_with_obstacles.insert(next_lane, Obstacle::far_away());
    }
}

#[derive(Copy, Clone)]
struct AddCar(LaneCar);

#[derive(Copy, Clone)]
struct UpdateObstacleOnNextLane(ID, Obstacle);

#[derive(Copy, Clone)]
struct AddOverlapObstacle(Obstacle);

recipient!(Lane, (&mut self, world: &mut World, self_id: ID) {
    AddCar: &AddCar(car) => {
        self.cars.insert(0, car);
    },

    Tick: &Tick{dt} => {
        let first_obstacle_on_any_next_lane = self.next_lanes_with_obstacles.pairs.iter()
            .min_by_key(|&&(_id, first_obstacle)| {first_obstacle.position})
            .map_or(Obstacle::far_away(), |&(_id, first_obstacle)| {Obstacle{
                position: OrderedFloat(*first_obstacle.position + self.length),
                velocity: first_obstacle.velocity
            }});

        for c in 0..self.cars.len() {
            let next_car = if c + 1 < self.cars.len() {*self.cars[c + 1]} else {first_obstacle_on_any_next_lane};
            let car = &mut self.cars[c];
            let next_car_acceleration = intelligent_driver_acceleration(car, &next_car);

            // TODO: optimize, avoid nested loop
            let next_overlap_obstacle = self.overlap_obstacles.iter().find(|obstacle| obstacle.position > car.position);
            let next_overlap_obstacle_acceleration = match next_overlap_obstacle {
                Some(obstacle) => intelligent_driver_acceleration(car, obstacle),
                None => INFINITY
            };

            car.acceleration = next_car_acceleration.min(next_overlap_obstacle_acceleration);
        }

        for car in &mut self.cars {
            *car.position += dt * car.velocity;
            car.velocity = car.max_velocity.min(car.velocity + dt * car.acceleration).max(0.0);
        }

        while self.cars.len() > 0 {
            let mut last_car = self.cars[self.cars.len() - 1];
            if *last_car.position > self.length {
                *last_car.position -= self.length;
                if let Some(next_lane) = self.next_lanes_with_obstacles.keys().next() {
                    world.send(next_lane, AddCar(last_car));
                }
                self.cars.pop();
            } else {break;}
        }

        let first_obstacle = match &self.cars.first() {
            &Some(ref car) => *car,
            &None => &first_obstacle_on_any_next_lane
        };
        for previous_lane in self.previous_lanes.iter() {
            world.send(*previous_lane, UpdateObstacleOnNextLane(self_id, *first_obstacle));
        }

        for overlap in self.overlaps.iter() {
            for car in self.cars.iter().filter(|car| car.position > overlap.start && car.position < overlap.end) {
                world.send(overlap.partner_lane, AddOverlapObstacle(match overlap.kind {
                    Parallel => Obstacle{
                        position: OrderedFloat(*car.position - *overlap.start + *overlap.partner_start),
                        velocity: car.velocity
                    },
                    Conflicting => Obstacle{
                        position: overlap.partner_start,
                        velocity: 0.0
                    }
                }));
            }
        }

        self.overlap_obstacles.clear();
    },

    UpdateObstacleOnNextLane: &UpdateObstacleOnNextLane(next_lane_id, first_obstacle) => {
        self.next_lanes_with_obstacles.insert(next_lane_id, first_obstacle);
    },

    AddOverlapObstacle: &AddOverlapObstacle(obstacle) => {
        self.overlap_obstacles.push(obstacle);
    }
});

fn intelligent_driver_acceleration(car: &LaneCar, obstacle: &Obstacle) -> f32 {
    // http://en.wikipedia.org/wiki/Intelligent_driver_model

    let car_length = 4.0;
    let acceleration = 5.0;
	let comfortable_breaking_deceleration : f32 = 4.0;
	let max_deceleration : f32 = 14.0;
	let desired_velocity = car.max_velocity;
	let safe_time_headway = 1.0;
	let acceleration_exponent = 4.0;
	let minimum_spacing = 10.0;

	let net_distance = *obstacle.position - *car.position - car_length;
	let velocity_difference = car.velocity - obstacle.velocity;

	let s_star = minimum_spacing + 0.0f32.max(car.velocity * safe_time_headway
		+ (car.velocity * velocity_difference / (2.0 * (acceleration * comfortable_breaking_deceleration).sqrt())));

    let result_acceleration = (-max_deceleration).max(acceleration * (
		1.0
		- (car.velocity / desired_velocity).powf(acceleration_exponent)
		- (s_star / net_distance).powf(2.0)
	));

	result_acceleration
}

pub fn setup(system: &mut ActorSystem) {
    system.add_swarm::<Lane>(InMemory("lane_actors", 512 * 64, 10));
    system.add_inbox::<AddCar, Lane>(InMemory("add_car", 512, 4));
    system.add_inbox::<UpdateObstacleOnNextLane, Lane>(InMemory("update_obstacle_on_next_lane", 512, 4));
    system.add_inbox::<AddOverlapObstacle, Lane>(InMemory("add_overlap_obstacle", 512, 4));
    system.add_inbox::<Tick, Lane>(InMemory("tick", 512, 4));

    system.world().send_to_individual::<_, Simulation>(AddSimulatable(system.broadcast_id::<Lane>()));

    setup_scenario(system);
}

fn setup_scenario(system: &mut ActorSystem) {
    let mut world = system.world();

    let mut lane1 = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(0.0, 0.0), P2::new(300.0, 0.0)),
            Segment::arc_with_direction(P2::new(300.0, 0.0), V2::new(1.0, 0.0), P2::new(300.0, 100.0))
        ]),
        None,
        None
    ));

    let mut lane3 = world.create(Lane::new(
        CPath::new(vec![
            Segment::arc_with_direction(P2::new(0.0, 100.0), V2::new(-1.0, 0.0), P2::new(0.0, 0.0))
        ]),
        Some(lane1.id),
        None
    ));

    let lane2 = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(300.0, 100.0), P2::new(0.0, 100.0))
        ]),
        Some(lane3.id),
        Some(lane1.id)
    ));

    let mut overlapping_lane = world.create(Lane::new(
        CPath::new(vec![
            Segment::line(P2::new(300.0, 10.0), P2::new(0.0, -10.0))
        ]),
        None,
        None
    ));

    lane1.add_next_lane(lane2.id);
    lane1.previous_lanes.push(lane3.id);
    lane3.previous_lanes.push(lane2.id);

    lane1.overlaps.push(Overlap{
        partner_lane: overlapping_lane.id,
        start: OrderedFloat(100.0),
        end: OrderedFloat(200.0),
        partner_start: OrderedFloat(100.0),
        partner_end: OrderedFloat(200.0),
        kind: Conflicting
    });

    overlapping_lane.overlaps.push(Overlap{
        partner_lane: lane1.id,
        start: OrderedFloat(100.0),
        end: OrderedFloat(200.0),
        partner_start: OrderedFloat(100.0),
        partner_end: OrderedFloat(200.0),
        kind: Conflicting
    });

    let lane1_id = lane1.id;
    let lane2_id = lane2.id;
    let overlapping_lane_id = overlapping_lane.id;

    world.start(lane1);
    world.start(lane2);
    world.start(lane3);
    world.start(overlapping_lane);

    let n_cars = 10;
    for i in 0..n_cars {
        world.send(lane1_id, AddCar(LaneCar{
            as_obstacle: Obstacle {
                position: OrderedFloat(n_cars as f32 * 5.0 - (i as f32 * 5.0)),
                velocity: 0.0,
            },
            trip: ID::invalid(),
            acceleration: 1.0,
            max_velocity: 22.0
        }));
    }

    world.send(lane2_id, AddCar(LaneCar{
        as_obstacle: Obstacle {
            position: OrderedFloat(5.0),
            velocity: 0.0,
        },
        trip: ID::invalid(),
        acceleration: 1.0,
        max_velocity: 0.0
    }));

    world.send(overlapping_lane_id, AddCar(LaneCar{
        as_obstacle: Obstacle {
            position: OrderedFloat(60.0),
            velocity: 0.0,
        },
        trip: ID::invalid(),
        acceleration: 1.0,
        max_velocity: 10.0
    }));
}<|endoftext|>


<commit_before>// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/theme.rs
// released under the MIT license by @defuz

use std::str::FromStr;

use super::settings::{ParseSettings, Settings};
use super::style::*;
use super::selector::*;
use super::theme::*;
use crate::parsing::ParseScopeError;

use self::ParseThemeError::*;

#[derive(Debug)]
pub enum ParseThemeError {
    IncorrectUnderlineOption,
    IncorrectFontStyle(String),
    IncorrectColor,
    IncorrectSyntax,
    IncorrectSettings,
    UndefinedSettings,
    UndefinedScopeSettings(String),
    ColorShemeScopeIsNotObject,
    ColorShemeSettingsIsNotObject,
    ScopeSelectorIsNotString(String),
    DuplicateSettings,
    ScopeParse(ParseScopeError),
}

impl From<ParseScopeError> for ParseThemeError {
    fn from(error: ParseScopeError) -> ParseThemeError {
        ScopeParse(error)
    }
}

impl FromStr for UnderlineOption {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<UnderlineOption, Self::Err> {
        Ok(match s {
            "underline" => UnderlineOption::Underline,
            "stippled_underline" => UnderlineOption::StippledUnderline,
            "squiggly_underline" => UnderlineOption::SquigglyUnderline,
            _ => return Err(IncorrectUnderlineOption),
        })
    }
}

impl ParseSettings for UnderlineOption {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<UnderlineOption, Self::Error> {
        match settings {
            Settings::String(value) => UnderlineOption::from_str(&value),
            _ => Err(IncorrectUnderlineOption),
        }
    }
}

impl FromStr for FontStyle {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<FontStyle, Self::Err> {
        let mut font_style = FontStyle::empty();
        for i in s.split_whitespace() {
            font_style.insert(match i {
                "bold" => FontStyle::BOLD,
                "underline" => FontStyle::UNDERLINE,
                "italic" => FontStyle::ITALIC,
                "normal" |
                "regular" => FontStyle::empty(),
                s => return Err(IncorrectFontStyle(s.to_owned())),
            })
        }
        Ok(font_style)
    }
}

impl ParseSettings for FontStyle {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<FontStyle, Self::Error> {
        match settings {
            Settings::String(value) => FontStyle::from_str(&value),
            c => Err(IncorrectFontStyle(c.to_string())),
        }
    }
}

impl FromStr for Color {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<Color, Self::Err> {
        let mut chars = s.chars();
        if chars.next() != Some('#') {
            return Err(IncorrectColor);
        }
        let mut d = Vec::new();
        for char in chars {
            d.push(char.to_digit(16).ok_or(IncorrectColor)? as u8);
        }
        Ok(match d.len() {
            3 => {
                Color {
                    r: d[0],
                    g: d[1],
                    b: d[2],
                    a: 255,
                }
            }
            6 => {
                Color {
                    r: d[0] * 16 + d[1],
                    g: d[2] * 16 + d[3],
                    b: d[4] * 16 + d[5],
                    a: 255,
                }
            }
            8 => {
                Color {
                    r: d[0] * 16 + d[1],
                    g: d[2] * 16 + d[3],
                    b: d[4] * 16 + d[5],
                    a: d[6] * 16 + d[7],
                }
            }
            _ => return Err(IncorrectColor),
        })
    }
}

impl ParseSettings for Color {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Color, Self::Error> {
        match settings {
            Settings::String(value) => Color::from_str(&value),
            _ => Err(IncorrectColor),
        }
    }
}

impl ParseSettings for StyleModifier {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<StyleModifier, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let font_style = match obj.remove("fontStyle") {
            Some(Settings::String(value)) => Some(FontStyle::from_str(&value)?),
            None => None,
            Some(c) => return Err(IncorrectFontStyle(c.to_string())),
        };
        let foreground = match obj.remove("foreground") {
            Some(Settings::String(value)) => Some(Color::from_str(&value)?),
            None => None,
            _ => return Err(IncorrectColor),
        };
        let background = match obj.remove("background") {
            Some(Settings::String(value)) => Some(Color::from_str(&value)?),
            None => None,
            _ => return Err(IncorrectColor),
        };

        Ok(StyleModifier {
            foreground,
            background,
            font_style,
        })
    }
}

impl ParseSettings for ThemeItem {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<ThemeItem, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let scope = match obj.remove("scope") {
            Some(Settings::String(value)) => ScopeSelectors::from_str(&value)?,
            _ => return Err(ScopeSelectorIsNotString(format!("{:?}", obj))),
        };
        let style = match obj.remove("settings") {
            Some(settings) => StyleModifier::parse_settings(settings)?,
            None => return Err(IncorrectSettings),
        };
        Ok(ThemeItem {
            scope,
            style,
        })
    }
}

impl ParseSettings for ThemeSettings {
    type Error = ParseThemeError;

    fn parse_settings(json: Settings) -> Result<ThemeSettings, Self::Error> {
        let mut settings = ThemeSettings::default();

        let obj = match json {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeSettingsIsNotObject),
        };

        for (key, value) in obj {
            match &key[..] {
                "foreground" => settings.foreground = Color::parse_settings(value).ok(),
                "background" => settings.background = Color::parse_settings(value).ok(),
                "caret" => settings.caret = Color::parse_settings(value).ok(),
                "lineHighlight" => settings.line_highlight = Color::parse_settings(value).ok(),
                "misspelling" => settings.misspelling = Color::parse_settings(value).ok(),
                "minimapBorder" => settings.minimap_border = Color::parse_settings(value).ok(),
                "accent" => settings.accent = Color::parse_settings(value).ok(),

                "popupCss" => settings.popup_css = value.as_str().map(|s| s.to_owned()),
                "phantomCss" => settings.phantom_css = value.as_str().map(|s| s.to_owned()),

                "bracketContentsForeground" => {
                    settings.bracket_contents_foreground = Color::parse_settings(value).ok()
                }
                "bracketContentsOptions" => {
                    settings.bracket_contents_options = UnderlineOption::parse_settings(value).ok()
                }
                "bracketsForeground" => {
                    settings.brackets_foreground = Color::parse_settings(value).ok()
                }
                "bracketsBackground" => {
                    settings.brackets_background = Color::parse_settings(value).ok()
                }
                "bracketsOptions" => {
                    settings.brackets_options = UnderlineOption::parse_settings(value).ok()
                }
                "tagsForeground" => settings.tags_foreground = Color::parse_settings(value).ok(),
                "tagsOptions" => {
                    settings.tags_options = UnderlineOption::parse_settings(value).ok()
                }
                "highlight" => settings.highlight = Color::parse_settings(value).ok(),
                "findHighlight" => settings.find_highlight = Color::parse_settings(value).ok(),
                "findHighlightForeground" => {
                    settings.find_highlight_foreground = Color::parse_settings(value).ok()
                }
                "gutter" => settings.gutter = Color::parse_settings(value).ok(),
                "gutterForeground" => {
                    settings.gutter_foreground = Color::parse_settings(value).ok()
                }
                "selection" => settings.selection = Color::parse_settings(value).ok(),
                "selectionForeground" => {
                    settings.selection_foreground = Color::parse_settings(value).ok()
                }
                "selectionBorder" => settings.selection_border = Color::parse_settings(value).ok(),
                "inactiveSelection" => {
                    settings.inactive_selection = Color::parse_settings(value).ok()
                }
                "inactiveSelectionForeground" => {
                    settings.inactive_selection_foreground = Color::parse_settings(value).ok()
                }
                "guide" => settings.guide = Color::parse_settings(value).ok(),
                "activeGuide" => settings.active_guide = Color::parse_settings(value).ok(),
                "stackGuide" => settings.stack_guide = Color::parse_settings(value).ok(),
                "shadow" => settings.shadow = Color::parse_settings(value).ok(),
                "shadowWidth"| // ignored
                "invisibles" | // ignored
                _ => (),
            }
        }
        Ok(settings)
    }
}

impl ParseSettings for Theme {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Theme, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(IncorrectSyntax),
        };
        let name = match obj.remove("name") {
            Some(Settings::String(name)) => Some(name),
            None => None,
            _ => return Err(IncorrectSyntax),
        };
        let author = match obj.remove("author") {
            Some(Settings::String(author)) => Some(author),
            None => None,
            _ => return Err(IncorrectSyntax),
        };
        let items = match obj.remove("settings") {
            Some(Settings::Array(items)) => items,
            _ => return Err(IncorrectSyntax),
        };
        let mut iter = items.into_iter();
        let settings = match iter.next() {
            Some(Settings::Object(mut obj)) => {
                match obj.remove("settings") {
                    Some(settings) => ThemeSettings::parse_settings(settings)?,
                    None => return Err(UndefinedSettings),
                }
            }
            _ => return Err(UndefinedSettings),
        };
        let mut scopes = Vec::new();
        for json in iter {
            // TODO option to disable best effort parsing and bubble up warnings
            if let Ok(item) = ThemeItem::parse_settings(json) {
                scopes.push(item);
            }
        }
        Ok(Theme {
            name,
            author,
            settings,
            scopes,
        })
    }
}
<commit_msg>Fix all clippy::wildcard_in_or_patterns warnings<commit_after>// Code based on https://github.com/defuz/sublimate/blob/master/src/core/syntax/theme.rs
// released under the MIT license by @defuz

use std::str::FromStr;

use super::settings::{ParseSettings, Settings};
use super::style::*;
use super::selector::*;
use super::theme::*;
use crate::parsing::ParseScopeError;

use self::ParseThemeError::*;

#[derive(Debug)]
pub enum ParseThemeError {
    IncorrectUnderlineOption,
    IncorrectFontStyle(String),
    IncorrectColor,
    IncorrectSyntax,
    IncorrectSettings,
    UndefinedSettings,
    UndefinedScopeSettings(String),
    ColorShemeScopeIsNotObject,
    ColorShemeSettingsIsNotObject,
    ScopeSelectorIsNotString(String),
    DuplicateSettings,
    ScopeParse(ParseScopeError),
}

impl From<ParseScopeError> for ParseThemeError {
    fn from(error: ParseScopeError) -> ParseThemeError {
        ScopeParse(error)
    }
}

impl FromStr for UnderlineOption {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<UnderlineOption, Self::Err> {
        Ok(match s {
            "underline" => UnderlineOption::Underline,
            "stippled_underline" => UnderlineOption::StippledUnderline,
            "squiggly_underline" => UnderlineOption::SquigglyUnderline,
            _ => return Err(IncorrectUnderlineOption),
        })
    }
}

impl ParseSettings for UnderlineOption {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<UnderlineOption, Self::Error> {
        match settings {
            Settings::String(value) => UnderlineOption::from_str(&value),
            _ => Err(IncorrectUnderlineOption),
        }
    }
}

impl FromStr for FontStyle {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<FontStyle, Self::Err> {
        let mut font_style = FontStyle::empty();
        for i in s.split_whitespace() {
            font_style.insert(match i {
                "bold" => FontStyle::BOLD,
                "underline" => FontStyle::UNDERLINE,
                "italic" => FontStyle::ITALIC,
                "normal" |
                "regular" => FontStyle::empty(),
                s => return Err(IncorrectFontStyle(s.to_owned())),
            })
        }
        Ok(font_style)
    }
}

impl ParseSettings for FontStyle {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<FontStyle, Self::Error> {
        match settings {
            Settings::String(value) => FontStyle::from_str(&value),
            c => Err(IncorrectFontStyle(c.to_string())),
        }
    }
}

impl FromStr for Color {
    type Err = ParseThemeError;

    fn from_str(s: &str) -> Result<Color, Self::Err> {
        let mut chars = s.chars();
        if chars.next() != Some('#') {
            return Err(IncorrectColor);
        }
        let mut d = Vec::new();
        for char in chars {
            d.push(char.to_digit(16).ok_or(IncorrectColor)? as u8);
        }
        Ok(match d.len() {
            3 => {
                Color {
                    r: d[0],
                    g: d[1],
                    b: d[2],
                    a: 255,
                }
            }
            6 => {
                Color {
                    r: d[0] * 16 + d[1],
                    g: d[2] * 16 + d[3],
                    b: d[4] * 16 + d[5],
                    a: 255,
                }
            }
            8 => {
                Color {
                    r: d[0] * 16 + d[1],
                    g: d[2] * 16 + d[3],
                    b: d[4] * 16 + d[5],
                    a: d[6] * 16 + d[7],
                }
            }
            _ => return Err(IncorrectColor),
        })
    }
}

impl ParseSettings for Color {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Color, Self::Error> {
        match settings {
            Settings::String(value) => Color::from_str(&value),
            _ => Err(IncorrectColor),
        }
    }
}

impl ParseSettings for StyleModifier {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<StyleModifier, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let font_style = match obj.remove("fontStyle") {
            Some(Settings::String(value)) => Some(FontStyle::from_str(&value)?),
            None => None,
            Some(c) => return Err(IncorrectFontStyle(c.to_string())),
        };
        let foreground = match obj.remove("foreground") {
            Some(Settings::String(value)) => Some(Color::from_str(&value)?),
            None => None,
            _ => return Err(IncorrectColor),
        };
        let background = match obj.remove("background") {
            Some(Settings::String(value)) => Some(Color::from_str(&value)?),
            None => None,
            _ => return Err(IncorrectColor),
        };

        Ok(StyleModifier {
            foreground,
            background,
            font_style,
        })
    }
}

impl ParseSettings for ThemeItem {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<ThemeItem, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeScopeIsNotObject),
        };
        let scope = match obj.remove("scope") {
            Some(Settings::String(value)) => ScopeSelectors::from_str(&value)?,
            _ => return Err(ScopeSelectorIsNotString(format!("{:?}", obj))),
        };
        let style = match obj.remove("settings") {
            Some(settings) => StyleModifier::parse_settings(settings)?,
            None => return Err(IncorrectSettings),
        };
        Ok(ThemeItem {
            scope,
            style,
        })
    }
}

impl ParseSettings for ThemeSettings {
    type Error = ParseThemeError;

    fn parse_settings(json: Settings) -> Result<ThemeSettings, Self::Error> {
        let mut settings = ThemeSettings::default();

        let obj = match json {
            Settings::Object(obj) => obj,
            _ => return Err(ColorShemeSettingsIsNotObject),
        };

        for (key, value) in obj {
            match &key[..] {
                "foreground" => settings.foreground = Color::parse_settings(value).ok(),
                "background" => settings.background = Color::parse_settings(value).ok(),
                "caret" => settings.caret = Color::parse_settings(value).ok(),
                "lineHighlight" => settings.line_highlight = Color::parse_settings(value).ok(),
                "misspelling" => settings.misspelling = Color::parse_settings(value).ok(),
                "minimapBorder" => settings.minimap_border = Color::parse_settings(value).ok(),
                "accent" => settings.accent = Color::parse_settings(value).ok(),

                "popupCss" => settings.popup_css = value.as_str().map(|s| s.to_owned()),
                "phantomCss" => settings.phantom_css = value.as_str().map(|s| s.to_owned()),

                "bracketContentsForeground" => {
                    settings.bracket_contents_foreground = Color::parse_settings(value).ok()
                }
                "bracketContentsOptions" => {
                    settings.bracket_contents_options = UnderlineOption::parse_settings(value).ok()
                }
                "bracketsForeground" => {
                    settings.brackets_foreground = Color::parse_settings(value).ok()
                }
                "bracketsBackground" => {
                    settings.brackets_background = Color::parse_settings(value).ok()
                }
                "bracketsOptions" => {
                    settings.brackets_options = UnderlineOption::parse_settings(value).ok()
                }
                "tagsForeground" => settings.tags_foreground = Color::parse_settings(value).ok(),
                "tagsOptions" => {
                    settings.tags_options = UnderlineOption::parse_settings(value).ok()
                }
                "highlight" => settings.highlight = Color::parse_settings(value).ok(),
                "findHighlight" => settings.find_highlight = Color::parse_settings(value).ok(),
                "findHighlightForeground" => {
                    settings.find_highlight_foreground = Color::parse_settings(value).ok()
                }
                "gutter" => settings.gutter = Color::parse_settings(value).ok(),
                "gutterForeground" => {
                    settings.gutter_foreground = Color::parse_settings(value).ok()
                }
                "selection" => settings.selection = Color::parse_settings(value).ok(),
                "selectionForeground" => {
                    settings.selection_foreground = Color::parse_settings(value).ok()
                }
                "selectionBorder" => settings.selection_border = Color::parse_settings(value).ok(),
                "inactiveSelection" => {
                    settings.inactive_selection = Color::parse_settings(value).ok()
                }
                "inactiveSelectionForeground" => {
                    settings.inactive_selection_foreground = Color::parse_settings(value).ok()
                }
                "guide" => settings.guide = Color::parse_settings(value).ok(),
                "activeGuide" => settings.active_guide = Color::parse_settings(value).ok(),
                "stackGuide" => settings.stack_guide = Color::parse_settings(value).ok(),
                "shadow" => settings.shadow = Color::parse_settings(value).ok(),
                _ => (), // E.g. "shadowWidth" and "invisibles" are ignored
            }
        }
        Ok(settings)
    }
}

impl ParseSettings for Theme {
    type Error = ParseThemeError;

    fn parse_settings(settings: Settings) -> Result<Theme, Self::Error> {
        let mut obj = match settings {
            Settings::Object(obj) => obj,
            _ => return Err(IncorrectSyntax),
        };
        let name = match obj.remove("name") {
            Some(Settings::String(name)) => Some(name),
            None => None,
            _ => return Err(IncorrectSyntax),
        };
        let author = match obj.remove("author") {
            Some(Settings::String(author)) => Some(author),
            None => None,
            _ => return Err(IncorrectSyntax),
        };
        let items = match obj.remove("settings") {
            Some(Settings::Array(items)) => items,
            _ => return Err(IncorrectSyntax),
        };
        let mut iter = items.into_iter();
        let settings = match iter.next() {
            Some(Settings::Object(mut obj)) => {
                match obj.remove("settings") {
                    Some(settings) => ThemeSettings::parse_settings(settings)?,
                    None => return Err(UndefinedSettings),
                }
            }
            _ => return Err(UndefinedSettings),
        };
        let mut scopes = Vec::new();
        for json in iter {
            // TODO option to disable best effort parsing and bubble up warnings
            if let Ok(item) = ThemeItem::parse_settings(json) {
                scopes.push(item);
            }
        }
        Ok(Theme {
            name,
            author,
            settings,
            scopes,
        })
    }
}
<|endoftext|>