<commit_before>extern crate mockito;

use std::net::TcpStream;
use std::io::{Read, Write, BufRead, BufReader};
use mockito::{SERVER_ADDRESS, mock, reset, Matcher};

fn request_stream(route: &str, headers: &str) -> TcpStream {
    let mut stream = TcpStream::connect(SERVER_ADDRESS).unwrap();
    let message = [route, " HTTP/1.1\r\n", headers, "\r\n"].join("");
    stream.write_all(message.as_bytes()).unwrap();

    stream
}

fn parse_stream(stream: TcpStream, content_length: usize) -> (String, Vec<String>, String) {
    let mut reader = BufReader::new(stream);

    let mut status_line = String::new();
    reader.read_line(&mut status_line).unwrap();

    let mut headers = vec![];
    loop {
        let mut header_line = String::new();
        reader.read_line(&mut header_line).unwrap();

        if header_line == "\r\n" { break }
        else { headers.push(header_line); }
    }

    let mut body = String::new();
    reader.take(content_length as u64).read_to_string(&mut body).unwrap();

    (status_line, headers, body)
}

fn request(route: &str, headers: &str, expected_content_length: usize) -> (String, Vec<String>, String) {
    parse_stream(request_stream(route, headers), expected_content_length)
}

#[test]
fn test_create_starts_the_server() {
    mock("GET", "/").with_body("hello").create();

    let stream = TcpStream::connect(SERVER_ADDRESS);
    assert!(stream.is_ok());
}

#[test]
fn test_simple_route_mock() {
    reset();

    let mocked_body = "world";
    mock("GET", "/hello").with_body(mocked_body).create();

    let (status_line, _, body) = request("GET /hello", "", 5);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status_line);
    assert_eq!(mocked_body, body);
}

#[test]
fn test_two_route_mocks() {
    reset();

    mock("GET", "/a").with_body("aaa").create();
    mock("GET", "/b").with_body("bbb").create();

    let (_, _, body_a) = request("GET /a", "", 3);

    assert_eq!("aaa", body_a);
    let (_, _, body_b) = request("GET /b", "", 3);
    assert_eq!("bbb", body_b);
}

#[test]
fn test_no_match_returns_501() {
    reset();

    mock("GET", "/").with_body("matched").create();

    let (status_line, _, _) = request("GET /nope", "", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status_line);
}

#[test]
fn test_match_header() {
    reset();

    mock("GET", "/")
        .match_header("content-type", "application/json")
        .with_body("{}")
        .create();

    mock("GET", "/")
        .match_header("content-type", "text/plain")
        .with_body("hello")
        .create();

    let (_, _, body_json) = request("GET /", "content-type: application/json\r\n", 2);
    assert_eq!("{}", body_json);

    let (_, _, body_text) = request("GET /", "content-type: text/plain\r\n", 5);
    assert_eq!("hello", body_text);
}

#[test]
fn test_match_header_is_case_insensitive_on_the_field_name() {
    reset();

    mock("GET", "/").match_header("content-type", "text/plain").create();

    let (uppercase_status_line, _, _) = request("GET /", "Content-Type: text/plain\r\n", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", uppercase_status_line);

    let (lowercase_status_line, _, _) = request("GET /", "content-type: text/plain\r\n", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", lowercase_status_line);
}

#[test]
fn test_match_multiple_headers() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", "text/plain")
        .match_header("Authorization", "secret")
        .with_body("matched")
        .create();

    let (_, _, body_matching) = request("GET /", "content-type: text/plain\r\nauthorization: secret\r\n", 7);
    assert_eq!("matched", body_matching);

    let (status_not_matching, _, _) = request("GET /", "content-type: text/plain\r\nauthorization: meh\r\n", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status_not_matching);
}

#[test]
fn test_match_header_any_matching() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", Matcher::Any)
        .with_body("matched")
        .create();

    let (_, _, body) = request("GET /", "content-type: something\r\n", 7);
    assert_eq!("matched", body);
}

#[test]
fn test_match_header_any_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", Matcher::Any)
        .with_body("matched")
        .create();

    let (status, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_match_header_missing_matching() {
    reset();

    mock("GET", "/")
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status);
}

#[test]
fn test_match_header_missing_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Authorization: something\r\n", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_match_multiple_header_conditions_matching() {
    reset();

    mock("GET", "/")
        .match_header("Hello", "World")
        .match_header("Content-Type", Matcher::Any)
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Hello: World\r\nContent-Type: something\r\n", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status);
}

#[test]
fn test_match_multiple_header_conditions_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("hello", "world")
        .match_header("Content-Type", Matcher::Any)
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Hello: World\r\n", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_mock_with_status() {
    reset();

    mock("GET", "/")
        .with_status(204)
        .with_body("")
        .create();

    let (status_line, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 204 <unknown status code>\r\n", status_line);
}

#[test]
fn test_mock_with_header() {
    reset();

    mock("GET", "/")
        .with_header("content-type", "application/json")
        .with_body("{}")
        .create();

    let (_, headers, _) = request("GET /", "", 0);
    assert!(headers.contains(&"content-type: application/json\r\n".to_string()));
}

#[test]
fn test_mock_with_multiple_headers() {
    reset();

    mock("GET", "/")
        .with_header("content-type", "application/json")
        .with_header("x-api-key", "1234")
        .with_body("{}")
        .create();

    let (_, headers, _) = request("GET /", "", 0);
    assert!(headers.contains(&"content-type: application/json\r\n".to_string()));
    assert!(headers.contains(&"x-api-key: 1234\r\n".to_string()));
}

#[test]
fn test_reset_clears_mocks() {
    reset();

    mock("GET", "/reset").create();

    let (working_status_line, _, _) = request("GET /reset", "", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);

    reset();

    let (reset_status_line, _, _) = request("GET /reset", "", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}

#[test]
fn test_mock_remove_clears_the_mock() {
    reset();

    let mut mock = mock("GET", "/");
    mock.create();

    let (working_status_line, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);

    mock.remove();

    let (reset_status_line, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}

#[test]
fn test_mock_create_for_is_only_available_during_the_closure_lifetime() {
    reset();

    mock("GET", "/").create_for( || {
        let (working_status_line, _, _) = request("GET /", "", 0);
        assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);
    });

    let (reset_status_line, _, _) = request("GET /", "", 0);
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}
<commit_msg>Test helper read content length internally<commit_after>extern crate mockito;

use std::net::TcpStream;
use std::io::{Read, Write, BufRead, BufReader};
use std::str::FromStr;
use mockito::{SERVER_ADDRESS, mock, reset, Matcher};

fn request_stream(route: &str, headers: &str) -> TcpStream {
    let mut stream = TcpStream::connect(SERVER_ADDRESS).unwrap();
    let message = [route, " HTTP/1.1\r\n", headers, "\r\n"].join("");
    stream.write_all(message.as_bytes()).unwrap();

    stream
}

fn parse_stream(stream: TcpStream) -> (String, Vec<String>, String) {
    let mut reader = BufReader::new(stream);

    let mut status_line = String::new();
    reader.read_line(&mut status_line).unwrap();

    let mut headers = vec![];
    let mut content_length: u64 = 0;
    loop {
        let mut header_line = String::new();
        reader.read_line(&mut header_line).unwrap();

        if header_line == "\r\n" { break }

        if header_line.starts_with("Content-Length:") {
            let mut parts = header_line.split(":");
            content_length = u64::from_str(parts.nth(1).unwrap().trim()).unwrap();
        }

        headers.push(header_line.trim_right().to_string());
    }

    let mut body = String::new();
    reader.take(content_length).read_to_string(&mut body).unwrap();

    (status_line, headers, body)
}

fn request(route: &str, headers: &str) -> (String, Vec<String>, String) {
    parse_stream(request_stream(route, headers))
}

#[test]
fn test_create_starts_the_server() {
    mock("GET", "/").with_body("hello").create();

    let stream = TcpStream::connect(SERVER_ADDRESS);
    assert!(stream.is_ok());
}

#[test]
fn test_simple_route_mock() {
    reset();

    let mocked_body = "world";
    mock("GET", "/hello").with_body(mocked_body).create();

    let (status_line, _, body) = request("GET /hello", "");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status_line);
    assert_eq!(mocked_body, body);
}

#[test]
fn test_two_route_mocks() {
    reset();

    mock("GET", "/a").with_body("aaa").create();
    mock("GET", "/b").with_body("bbb").create();

    let (_, _, body_a) = request("GET /a", "");

    assert_eq!("aaa", body_a);
    let (_, _, body_b) = request("GET /b", "");
    assert_eq!("bbb", body_b);
}

#[test]
fn test_no_match_returns_501() {
    reset();

    mock("GET", "/").with_body("matched").create();

    let (status_line, _, _) = request("GET /nope", "");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status_line);
}

#[test]
fn test_match_header() {
    reset();

    mock("GET", "/")
        .match_header("content-type", "application/json")
        .with_body("{}")
        .create();

    mock("GET", "/")
        .match_header("content-type", "text/plain")
        .with_body("hello")
        .create();

    let (_, _, body_json) = request("GET /", "content-type: application/json\r\n");
    assert_eq!("{}", body_json);

    let (_, _, body_text) = request("GET /", "content-type: text/plain\r\n");
    assert_eq!("hello", body_text);
}

#[test]
fn test_match_header_is_case_insensitive_on_the_field_name() {
    reset();

    mock("GET", "/").match_header("content-type", "text/plain").create();

    let (uppercase_status_line, _, _) = request("GET /", "Content-Type: text/plain\r\n");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", uppercase_status_line);

    let (lowercase_status_line, _, _) = request("GET /", "content-type: text/plain\r\n");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", lowercase_status_line);
}

#[test]
fn test_match_multiple_headers() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", "text/plain")
        .match_header("Authorization", "secret")
        .with_body("matched")
        .create();

    let (_, _, body_matching) = request("GET /", "content-type: text/plain\r\nauthorization: secret\r\n");
    assert_eq!("matched", body_matching);

    let (status_not_matching, _, _) = request("GET /", "content-type: text/plain\r\nauthorization: meh\r\n");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status_not_matching);
}

#[test]
fn test_match_header_any_matching() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", Matcher::Any)
        .with_body("matched")
        .create();

    let (_, _, body) = request("GET /", "content-type: something\r\n");
    assert_eq!("matched", body);
}

#[test]
fn test_match_header_any_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("Content-Type", Matcher::Any)
        .with_body("matched")
        .create();

    let (status, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_match_header_missing_matching() {
    reset();

    mock("GET", "/")
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status);
}

#[test]
fn test_match_header_missing_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Authorization: something\r\n");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_match_multiple_header_conditions_matching() {
    reset();

    mock("GET", "/")
        .match_header("Hello", "World")
        .match_header("Content-Type", Matcher::Any)
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Hello: World\r\nContent-Type: something\r\n");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", status);
}

#[test]
fn test_match_multiple_header_conditions_not_matching() {
    reset();

    mock("GET", "/")
        .match_header("hello", "world")
        .match_header("Content-Type", Matcher::Any)
        .match_header("Authorization", Matcher::Missing)
        .create();

    let (status, _, _) = request("GET /", "Hello: World\r\n");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", status);
}

#[test]
fn test_mock_with_status() {
    reset();

    mock("GET", "/")
        .with_status(204)
        .with_body("")
        .create();

    let (status_line, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 204 <unknown status code>\r\n", status_line);
}

#[test]
fn test_mock_with_header() {
    reset();

    mock("GET", "/")
        .with_header("content-type", "application/json")
        .with_body("{}")
        .create();

    let (_, headers, _) = request("GET /", "");
    assert!(headers.contains(&"content-type: application/json".to_string()));
}

#[test]
fn test_mock_with_multiple_headers() {
    reset();

    mock("GET", "/")
        .with_header("content-type", "application/json")
        .with_header("x-api-key", "1234")
        .with_body("{}")
        .create();

    let (_, headers, _) = request("GET /", "");
    assert!(headers.contains(&"content-type: application/json".to_string()));
    assert!(headers.contains(&"x-api-key: 1234".to_string()));
}

#[test]
fn test_reset_clears_mocks() {
    reset();

    mock("GET", "/reset").create();

    let (working_status_line, _, _) = request("GET /reset", "");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);

    reset();

    let (reset_status_line, _, _) = request("GET /reset", "");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}

#[test]
fn test_mock_remove_clears_the_mock() {
    reset();

    let mut mock = mock("GET", "/");
    mock.create();

    let (working_status_line, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);

    mock.remove();

    let (reset_status_line, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}

#[test]
fn test_mock_create_for_is_only_available_during_the_closure_lifetime() {
    reset();

    mock("GET", "/").create_for( || {
        let (working_status_line, _, _) = request("GET /", "");
        assert_eq!("HTTP/1.1 200 <unknown status code>\r\n", working_status_line);
    });

    let (reset_status_line, _, _) = request("GET /", "");
    assert_eq!("HTTP/1.1 501 Not Implemented\r\n", reset_status_line);
}
<|endoftext|>


<commit_before>#[macro_use(owned_tree)]
extern crate entmut;

use ::entmut::Nav;
use ::entmut::owned::Tree;
use std::borrow::Borrow;

// This will define macros for generalized tests of Nav and Editor impls.
// #[cfg(test)]
// mod template;

#[test]
#[allow(unused_variables)]
fn nav_instantiation() {
    let t = owned_tree!["a"];
    let v = t.view();
}

#[test]
fn nav_preserves_leaf_topology() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert![v.at_leaf()];
    assert![v.at_root()];
    assert_eq![0, v.child_count()];
}

// #[test]
// fn nav_preserves_leaf_data() {
//     let t = owned_tree!["a"];
//     let t_data_view = &t.data;
//     let v = t.view();
//     let data: &str = v.borrow();
//     assert_eq!["a", data];
//     assert_eq![t_data_view, data];
// }
<commit_msg>First data-based integration test.<commit_after>#[macro_use(owned_tree)]
extern crate entmut;

use ::entmut::Nav;
use ::entmut::owned::Tree;

// This will define macros for generalized tests of Nav and Editor impls.
// #[cfg(test)]
// mod template;

#[test]
#[allow(unused_variables)]
fn nav_instantiation() {
    let t = owned_tree!["a"];
    let v = t.view();
}

#[test]
fn nav_preserves_leaf_topology() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert![v.at_leaf()];
    assert![v.at_root()];
    assert_eq![0, v.child_count()];
}

#[test]
fn nav_preserves_leaf_data() {
    let t = owned_tree!["a"];
    let v = t.view();
    assert_eq!["a", *v];
}
<|endoftext|>


<commit_before>use cap::Cap;
use crates_index::*;
use rayon::iter::ParallelIterator;
use std::alloc;

#[global_allocator]
static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::max_value());

#[test]
fn mem_usage() {
    let index = Index::new_cargo_default().unwrap();

    let before = ALLOCATOR.allocated();
    // let all_crates: Vec<_> = index.crates().collect();
    let all_crates: Vec<_> = index.crates_parallel().map(|c| c.unwrap()).collect();
    let after = ALLOCATOR.allocated();
    let used = after - before;
    assert!(all_crates.len() > 89000);
    eprintln!(
        "used mem: {}B for {} crates, {}B per crate",
        used,
        all_crates.len(),
        used / all_crates.len()
    );
    assert!(used / all_crates.len() < 5100);
}
<commit_msg>The index keeps growing<commit_after>use cap::Cap;
use crates_index::*;
use rayon::iter::ParallelIterator;
use std::alloc;

#[global_allocator]
static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::max_value());

#[test]
fn mem_usage() {
    let index = Index::new_cargo_default().unwrap();

    let before = ALLOCATOR.allocated();
    // let all_crates: Vec<_> = index.crates().collect();
    let all_crates: Vec<_> = index.crates_parallel().map(|c| c.unwrap()).collect();
    let after = ALLOCATOR.allocated();
    let used = after - before;
    assert!(all_crates.len() > 89000);
    eprintln!(
        "used mem: {}B for {} crates, {}B per crate",
        used,
        all_crates.len(),
        used / all_crates.len()
    );
    assert!(used / all_crates.len() < 6000);
}
<|endoftext|>


<commit_before>use crate::core::card::Card;
use crate::core::deck::Deck;
use std::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};

extern crate rand;
use rand::seq::*;
use rand::thread_rng;

/// `FlatDeck` is a deck of cards that allows easy
/// indexing into the cards. It does not provide
/// contains methods.
#[derive(Debug)]
pub struct FlatDeck {
    /// Card storage.
    cards: Vec<Card>,
}

impl FlatDeck {
    /// How many cards are there in the deck ?
    pub fn len(&self) -> usize {
        self.cards.len()
    }
    /// Have all cards been dealt ?
    /// This probably won't be used as it's unlikely
    /// that someone will deal all 52 cards from a deck.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Give a random sample of the cards still left in the deck
    pub fn sample(&self, n: usize) -> Vec<Card> {
        let mut rng = thread_rng();
        self.cards.choose_multiple(&mut rng, n).cloned().collect()
    }

    /// Randomly shuffle the flat deck.
    /// This will ensure the there's no order to the deck.
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        self.cards.shuffle(&mut rng)
    }

    /// Deal a card if there is one there to deal.
    /// None if the deck is empty
    pub fn deal(&mut self) -> Option<Card> {
        self.cards.pop()
    }
}

impl Index<usize> for FlatDeck {
    type Output = Card;
    fn index(&self, index: usize) -> &Card {
        &self.cards[index]
    }
}
impl Index<Range<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: Range<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeTo<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeTo<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFrom<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFrom<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFull> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFull) -> &[Card] {
        &self.cards[index]
    }
}

impl From<Vec<Card>> for FlatDeck {
    fn from(value: Vec<Card>) -> Self {
        Self { cards: value }
    }
}

/// Allow creating a flat deck from a Deck
impl From<Deck> for FlatDeck {
    /// Flatten this deck, consuming it to produce a `FlatDeck` that's
    /// easier to get random access to.
    fn from(value: Deck) -> Self {
        Self {
            cards: value.into_iter().collect(),
        }
    }
}
<commit_msg>Test for from vec for flat deck<commit_after>use crate::core::card::Card;
use crate::core::deck::Deck;
use std::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};

extern crate rand;
use rand::seq::*;
use rand::thread_rng;

/// `FlatDeck` is a deck of cards that allows easy
/// indexing into the cards. It does not provide
/// contains methods.
#[derive(Debug)]
pub struct FlatDeck {
    /// Card storage.
    cards: Vec<Card>,
}

impl FlatDeck {
    /// How many cards are there in the deck ?
    pub fn len(&self) -> usize {
        self.cards.len()
    }
    /// Have all cards been dealt ?
    /// This probably won't be used as it's unlikely
    /// that someone will deal all 52 cards from a deck.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Give a random sample of the cards still left in the deck
    pub fn sample(&self, n: usize) -> Vec<Card> {
        let mut rng = thread_rng();
        self.cards.choose_multiple(&mut rng, n).cloned().collect()
    }

    /// Randomly shuffle the flat deck.
    /// This will ensure the there's no order to the deck.
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        self.cards.shuffle(&mut rng)
    }

    /// Deal a card if there is one there to deal.
    /// None if the deck is empty
    pub fn deal(&mut self) -> Option<Card> {
        self.cards.pop()
    }
}

impl Index<usize> for FlatDeck {
    type Output = Card;
    fn index(&self, index: usize) -> &Card {
        &self.cards[index]
    }
}
impl Index<Range<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: Range<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeTo<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeTo<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFrom<usize>> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFrom<usize>) -> &[Card] {
        &self.cards[index]
    }
}
impl Index<RangeFull> for FlatDeck {
    type Output = [Card];
    fn index(&self, index: RangeFull) -> &[Card] {
        &self.cards[index]
    }
}

impl From<Vec<Card>> for FlatDeck {
    fn from(value: Vec<Card>) -> Self {
        Self { cards: value }
    }
}

/// Allow creating a flat deck from a Deck
impl From<Deck> for FlatDeck {
    /// Flatten this deck, consuming it to produce a `FlatDeck` that's
    /// easier to get random access to.
    fn from(value: Deck) -> Self {
        Self {
            cards: value.into_iter().collect(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::card::{Suit, Value};

    #[test]
    fn test_deck_from() {
        let fd: FlatDeck = Deck::default().into();
        assert_eq!(52, fd.len());
    }

    #[test]
    fn test_from_vec() {
        let c = Card {
            value: Value::Nine,
            suit: Suit::Heart,
        };
        let v = vec![c];

        let mut flat_deck: FlatDeck = v.into();

        assert_eq!(1, flat_deck.len());
        assert_eq!(c, flat_deck.deal().unwrap());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
//! This is a webui about to replace the TUI, to be nice, better accessable, and
//! new technology using websockets
//! todo: this file must be logically ordered

mod json;
mod pages;

use super::{
    super::{
        common::startup::{StartUp, SyncStartUp},
        config,
        ctrl::InternalUiMsg,
    },
    CollectionPathAlive, PeerRepresentation,
};
use actix::prelude::{StreamHandler, *};
use actix::{Actor, ActorContext, AsyncContext, Context, Handler};
use actix_web::{
    web::{self, HttpResponse, Json},
    App, Error, HttpRequest, HttpServer,
};
use actix_web_actors::ws;
use get_if_addrs;
use json::WSJson;
use std::{
    fmt, io,
    net::IpAddr,
    string::String,
    sync::{
        mpsc::{Receiver, Sender},
        Arc, Mutex,
    },
    time::{Duration, Instant},
    vec::Vec,
};

/// How often heartbeat pings are sent
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
/// How long before lack of client response causes a timeout
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);

pub struct WebServerState {
    id: PeerRepresentation,
    nr_connections: Arc<Mutex<usize>>,
}

#[derive(Message)]
#[rtype(result = "()")]
struct RegisterWSClient {
    addr: Addr<MyWebSocket>,
}
#[derive(Message)]
#[rtype(result = "()")]
struct ServerEvent {
    event: Json<WSJson>,
}

/// Monitors all connected websockets,
/// and therefore distributes the internal incoming
/// messages.
struct WSServerMonitor {
    receiver: Receiver<InternalUiMsg>,
    listeners: Vec<Addr<MyWebSocket>>, // todo: these are WSCli bla
    paths: Vec<String>,
    startup_sync: Sender<SyncStartUp>, // todo: move this to after "start" from browser!!!!!!
}

impl Actor for WSServerMonitor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("server monitor got started");

        //        ctx.run_later(Duration::from_millis(0), |act, _| {
        StartUp::block_on_sync(self.startup_sync.clone(), "webui");
        //        });

        let cloned_paths = self.paths.clone();
        // send init data to ui
        // todo: waiting is of course not the solution
        ctx.run_later(Duration::from_millis(3000), move |act, _| {
            trace!("........... informing");
            for ws in &act.listeners {
                let answer = Json(json::generate_init_data(&cloned_paths.clone()));
                ws.do_send(ServerEvent { event: answer });
            }
        });

        let all_ws_initialized = false;
        // todo: this is crap of course, polling in 20ms and try_recv on a receiver
        //       but for now it's fine!!!

        ctx.run_interval(Duration::from_millis(20), |act, _| {
            //loop {

            if let Ok(internal_message) = act.receiver.try_recv() {
                // inform all listeners
                match json::convert_internal_message(&internal_message) {
                    Ok(response_json) => {
                        for ws in &act.listeners {
                            ws.do_send(ServerEvent {
                                event: Json(response_json.clone()),
                            });
                        }
                    }
                    Err(attribute) => {
                        warn!(
                            "No, we don't want the internal variable '{:?}' sent out!",
                            attribute
                        );
                    }
                }
            }
        });
    }
}
impl Handler<RegisterWSClient> for WSServerMonitor {
    type Result = ();

    fn handle(&mut self, msg: RegisterWSClient, _: &mut Context<Self>) {
        info!("something done here");
        self.listeners.push(msg.addr);
    }
}

/// needs to be serializable for json

struct JSONResponse {
    cmd: WebCommand,
}

#[derive(Serialize)]
enum WebCommand {
    Started,
    #[allow(dead_code)]
    NewMdnsClient(String),
}

impl fmt::Display for JSONResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.cmd)
    }
}
impl fmt::Display for WebCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            WebCommand::Started => write!(f, "Started"),
            WebCommand::NewMdnsClient(param) => write!(f, "MDNS_IP: {}", param),
        }
    }
}

/// dynamic development files
//#[get("/app.js")]
//fn app_js() -> Result<fs::NamedFile> {
//Ok(fs::NamedFile::open("src/ctrl/webui/js/app.js")?)
//}

pub struct WebUI {
    id: PeerRepresentation,
    serve_others: bool,
    paths: Vec<String>,
}

impl WebUI {
    pub fn new(id: PeerRepresentation, serve_others: bool, paths: Vec<String>) -> Self {
        Self {
            id,
            serve_others,
            paths,
        }
    }

    pub async fn run(
        &self,
        receiver: Receiver<InternalUiMsg>,
        sync_startup: Sender<SyncStartUp>,
    ) -> io::Result<()> {
        let connection_count = Arc::new(Mutex::new(0));

        let local_addresses = get_if_addrs::get_if_addrs().unwrap();

        // data
        let initial_state = Arc::new(Mutex::new(WebServerState {
            id: self.id.clone(),
            nr_connections: connection_count.clone(),
        }));

        // very important: after this the actix system, message loop,
        // whatever ... is UP!!!
        let sys = actix::System::new("http-server");

        let web_socket_handler = Arc::new(Mutex::new(
            WSServerMonitor {
                receiver,
                listeners: vec![],
                paths: self.paths.clone(),
                startup_sync: sync_startup,
            }
            .start(),
        ));

        // take all local addresses and start if necessary
        // one server with multiple binds
        let web_server = local_addresses
            .into_iter()
            .filter(|ipaddr| {
                let name = ipaddr.name.clone();
                // only use loopback addresses no 2nd ethernet cards
                if ipaddr.addr.is_loopback() {
                    info!(
                        "{} {:?} is a loopback device, good!",
                        ipaddr.addr.ip().to_string(),
                        name
                    );
                    true
                } else {
                    warn!("{} is not a loopback device!", ipaddr.addr.ip().to_string());
                    true
                }
            })
            .fold(
                Ok(HttpServer::new(move || {
                    App::new()
                        // each server has an initial state (e.g. 0 connections)
                        .data(web_socket_handler.clone())
                        .data(initial_state.clone())
                        .service(web::resource("/app.js").to(pages::js_app))
                        .default_service(web::resource("").to(pages::single_page))
                        //.default_service(web::resource("").to(static_pages::dyn_devel_html)) // Todo: only for devel
                        //.service(web::resource("/app.js").to(static_pages::dyn_devel_js)) // todo: only for devel
                        .service(web::resource("/jquery.min.js").to(|| {
                            HttpResponse::Ok()
                                .content_type("application/javascript; charset=utf-8")
                                .body(*config::webui::jquery::JS_JQUERY)
                        }))
                        .service(web::resource("/ws_events_dispatcher.js").to(|| {
                            HttpResponse::Ok()
                                .content_type("application/javascript; charset=utf-8")
                                .body(*config::webui::JS_WS_EVENT_DISPATCHER)
                        }))
                        .service(web::resource("favicon.png").to(|| {
                            HttpResponse::Ok()
                                .content_type("image/png")
                                .body(*config::webui::FAVICON)
                        }))
                        .service(web::resource("sheep.svg").to(|| {
                            HttpResponse::Ok()
                                .content_type("image/svg+xml")
                                .body(*config::webui::PIC_SHEEP)
                        }))
                        .service(
                            web::resource("/css/{name}").route(web::get().to(pages::bootstrap_css)),
                        )
                        .service(
                            web::resource("/js/{name}").route(web::get().to(pages::bootstrap_js)),
                        )
                        .service(web::resource("/ws").route(web::get().to(WebUI::websocket_answer)))
                })),
                |web_server_binding_chain: Result<HttpServer<_, _, _, _>, io::Error>, ipaddr| {
                    web_server_binding_chain.and_then(|webserver| {
                        let bind_format = match ipaddr.addr.ip() {
                            IpAddr::V4(ipv4) => {
                                format!("{}:{:?}", ipv4.to_string(), config::net::PORT_WEBSOCKET)
                            }
                            IpAddr::V6(ipv6) => {
                                format!("{}:{:?}", ipv6.to_string(), config::net::PORT_WEBSOCKET)
                            }
                        };
                        let try_bind = webserver.bind(bind_format.clone()).map_err(|error| {
                            error!("On IP ({:?}): {:?}", bind_format, error);
                            error
                        })?;
                        Ok(try_bind)
                    })
                },
            );
        web_server?.run();
        sys.run()
    }

    async fn websocket_answer(
        req: HttpRequest,
        stream: web::Payload,
        data: web::Data<Arc<Mutex<Addr<WSServerMonitor>>>>,
    ) -> Result<HttpResponse, Error> {
        trace!("new websocket answered!");
        let (addr, res) = ws::start_with_addr(MyWebSocket::new(), &req, stream)?;
        data.lock().unwrap().do_send(RegisterWSClient { addr });
        Ok(res)
    }
}

/// websocket connection is long running connection, it easier
/// to handle with an actor
struct MyWebSocket {
    /// Client must send ping at least once per 10 seconds (CLIENT_TIMEOUT),
    /// otherwise we drop connection.
    hb: Instant,
    browser_sent_start: bool,
}

impl Actor for MyWebSocket {
    type Context = ws::WebsocketContext<Self>;

    /// Method is called on actor start. We start the heartbeat process here.
    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("heartbeat started");
        self.hb(ctx);
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        // On system stop this may or may not run
        warn!("shutting down whole actix-system");
        actix::System::current().stop();
    }
}
impl Handler<ServerEvent> for MyWebSocket {
    type Result = ();

    fn handle(&mut self, msg: ServerEvent, ctx: &mut Self::Context) {
        if !self.browser_sent_start {
            // send initial json
        }
        trace!("send: {}", msg.event.to_string());
        ctx.text(msg.event.to_string());
    }
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWebSocket {
    /// Handler for `ws::Message`
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        // process websocket messages
        match msg {
            Ok(good_message) => {
                trace!("hb handler: {:?}", good_message);
                match good_message {
                    ws::Message::Ping(msg) => {
                        self.hb = Instant::now();
                        ctx.pong(&msg);
                    }
                    ws::Message::Pong(_) => {
                        self.hb = Instant::now();
                    }
                    ws::Message::Text(text) => {
                        let m = text.trim();
                        // /command
                        if m.starts_with('/') {
                            let v: Vec<&str> = m.splitn(2, ' ').collect();
                            match v[0] {
                                "/start" => {
                                    ctx.text(
                                        Json(JSONResponse {
                                            cmd: WebCommand::Started,
                                        })
                                        .to_string(),
                                    );
                                    self.browser_sent_start = true;
                                }
                                _ => ctx.text(format!("!!! unknown command: {:?}", m)),
                            }
                        }
                    }
                    ws::Message::Binary(bin) => ctx.binary(bin),
                    ws::Message::Close(_) => {
                        ctx.stop();
                    }
                    ws::Message::Nop => (),
                    ws::Message::Continuation(_) => (), // todo: what's this?
                }
            }
            Err(e) => warn!("message was not good {}", e),
        }
    }
}

impl MyWebSocket {
    fn new() -> Self {
        Self {
            hb: Instant::now(),
            browser_sent_start: false,
        }
    }

    /// helper method that sends ping to client every second.
    ///
    /// also this method checks heartbeats from client
    fn hb(&self, ctx: &mut <Self as Actor>::Context) {
        ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
            // check client heartbeats
            if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
                // heartbeat timed out
                error!("Websocket Client heartbeat failed, disconnecting!");

                // stop actor
                ctx.stop();

                // don't try to send a ping
                return;
            }

            ctx.ping(b"");
        });
    }
}
<commit_msg>[webui] remove unclear, unnecessary parts, heartbeat probably not needed since websockets<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
//! This is a webui about to replace the TUI, to be nice, better accessable, and
//! new technology using websockets
// todo: this file must be logically ordered (websocket, actors, http server, etc.)

mod json;
mod pages;

use super::{
    super::{
        common::startup::{StartUp, SyncStartUp},
        config,
        ctrl::InternalUiMsg,
    },
    CollectionPathAlive, PeerRepresentation,
};
use actix::prelude::{StreamHandler, *};
use actix::{Actor, ActorContext, AsyncContext, Context, Handler};
use actix_web::{
    web::{self, HttpResponse, Json},
    App, Error, HttpRequest, HttpServer,
};
use actix_web_actors::ws;
use get_if_addrs;
use json::WSJson;
use std::{
    fmt, io,
    net::IpAddr,
    string::String,
    sync::{
        mpsc::{Receiver, Sender},
        Arc, Mutex,
    },
    time::{Duration, Instant},
    vec::Vec,
};

/// How often heartbeat pings are sent
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
/// How long before lack of client response causes a timeout
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);

pub struct WebServerState {
    id: PeerRepresentation,
    nr_connections: Arc<Mutex<usize>>,
}

#[derive(Message)]
#[rtype(result = "()")]
struct RegisterWSClient {
    addr: Addr<MyWebSocket>,
}
#[derive(Message)]
#[rtype(result = "()")]
struct ServerEvent {
    event: Json<WSJson>,
}

/// Monitors all connected websockets,
/// and therefore distributes the internal incoming
/// messages.
struct WSServerMonitor {
    receiver: Receiver<InternalUiMsg>,
    listeners: Vec<Addr<MyWebSocket>>, // todo: these are WSCli bla
    paths: Vec<String>,
    startup_sync: Sender<SyncStartUp>, // todo: move this to after "start" from browser!!!!!!
}

impl Actor for WSServerMonitor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("server monitor got started");

        // send Ready to go to UI -> Main Threads ...
        // todo: find the right place ...!! Be careful, this doesn't work everywhere and leads to
        //       panics!
        ctx.run_later(Duration::from_millis(10), move |act, _| {
            info!("bloooooooooooooooooooooooo");
            StartUp::block_on_sync(act.startup_sync.clone(), "webui");
        });

        // All ctx. result "probably"(?) in an async closures ... hence none of these closures
        // shall not block at all!!

        // send init data after a certain time .... yet poor, timeouts are not a solution
        // todo: waiting is of course not the solution
        let cloned_paths = self.paths.clone();
        ctx.run_later(Duration::from_millis(3000), move |act, _| {
            trace!("sending init!");
            for ws in &act.listeners {
                let answer = Json(json::generate_init_data(&cloned_paths.clone()));
                ws.do_send(ServerEvent { event: answer });
            }
        });

        // todo: this is crap of course, polling in 20ms and try_recv on a receiver
        //       but for now it's fine!!!
        ctx.run_interval(Duration::from_millis(20), |act, _| {
            //loop {

            if let Ok(internal_message) = act.receiver.try_recv() {
                // inform all listeners
                match json::convert_internal_message(&internal_message) {
                    Ok(response_json) => {
                        for ws in &act.listeners {
                            ws.do_send(ServerEvent {
                                event: Json(response_json.clone()),
                            });
                        }
                    }
                    Err(attribute) => {
                        warn!(
                            "No, we don't want the internal variable '{:?}' sent out!",
                            attribute
                        );
                    }
                }
            }
        });
    }
}
impl Handler<RegisterWSClient> for WSServerMonitor {
    type Result = ();

    fn handle(&mut self, msg: RegisterWSClient, _ctx: &mut Context<Self>) {
        info!("something done here");
        self.listeners.push(msg.addr);
    }
}

/// dynamic development files
//#[get("/app.js")]
//fn app_js() -> Result<fs::NamedFile> {
//Ok(fs::NamedFile::open("src/ctrl/webui/js/app.js")?)
//}

pub struct WebUI {
    id: PeerRepresentation,
    serve_others: bool,
    paths: Vec<String>,
}

impl WebUI {
    pub fn new(id: PeerRepresentation, serve_others: bool, paths: Vec<String>) -> Self {
        Self {
            id,
            serve_others,
            paths,
        }
    }

    pub async fn run(
        &self,
        receiver: Receiver<InternalUiMsg>,
        sync_startup: Sender<SyncStartUp>,
    ) -> io::Result<()> {
        let connection_count = Arc::new(Mutex::new(0));

        let local_addresses = get_if_addrs::get_if_addrs().unwrap();

        // data
        let initial_state = Arc::new(Mutex::new(WebServerState {
            id: self.id.clone(),
            nr_connections: connection_count.clone(),
        }));

        // very important: after this the actix system, message loop,
        // whatever ... is UP!!!
        let sys = actix::System::new("http-server");

        let web_socket_handler = Arc::new(Mutex::new(
            WSServerMonitor {
                receiver,
                listeners: vec![],
                paths: self.paths.clone(),
                startup_sync: sync_startup,
            }
            .start(),
        ));

        // take all local addresses and start if necessary
        // one server with multiple binds
        let web_server = local_addresses
            .into_iter()
            .filter(|ipaddr| {
                let name = ipaddr.name.clone();
                // only use loopback addresses no 2nd ethernet cards
                if ipaddr.addr.is_loopback() {
                    info!(
                        "{} {:?} is a loopback device, good!",
                        ipaddr.addr.ip().to_string(),
                        name
                    );
                    true
                } else {
                    warn!("{} is not a loopback device!", ipaddr.addr.ip().to_string());
                    true
                }
            })
            .fold(
                Ok(HttpServer::new(move || {
                    App::new()
                        // each server has an initial state (e.g. 0 connections)
                        .data(web_socket_handler.clone())
                        .data(initial_state.clone())
                        .service(web::resource("/app.js").to(pages::js_app))
                        .default_service(web::resource("").to(pages::single_page))
                        //.default_service(web::resource("").to(static_pages::dyn_devel_html)) // Todo: only for devel
                        //.service(web::resource("/app.js").to(static_pages::dyn_devel_js)) // todo: only for devel
                        .service(web::resource("/jquery.min.js").to(|| {
                            HttpResponse::Ok()
                                .content_type("application/javascript; charset=utf-8")
                                .body(*config::webui::jquery::JS_JQUERY)
                        }))
                        .service(web::resource("/ws_events_dispatcher.js").to(|| {
                            HttpResponse::Ok()
                                .content_type("application/javascript; charset=utf-8")
                                .body(*config::webui::JS_WS_EVENT_DISPATCHER)
                        }))
                        .service(web::resource("favicon.png").to(|| {
                            HttpResponse::Ok()
                                .content_type("image/png")
                                .body(*config::webui::FAVICON)
                        }))
                        .service(web::resource("sheep.svg").to(|| {
                            HttpResponse::Ok()
                                .content_type("image/svg+xml")
                                .body(*config::webui::PIC_SHEEP)
                        }))
                        .service(
                            web::resource("/css/{name}").route(web::get().to(pages::bootstrap_css)),
                        )
                        .service(
                            web::resource("/js/{name}").route(web::get().to(pages::bootstrap_js)),
                        )
                        .service(web::resource("/ws").route(web::get().to(WebUI::websocket_answer)))
                })),
                |web_server_binding_chain: Result<HttpServer<_, _, _, _>, io::Error>, ipaddr| {
                    web_server_binding_chain.and_then(|webserver| {
                        let bind_format = match ipaddr.addr.ip() {
                            IpAddr::V4(ipv4) => {
                                format!("{}:{:?}", ipv4.to_string(), config::net::PORT_WEBSOCKET)
                            }
                            IpAddr::V6(ipv6) => {
                                format!("{}:{:?}", ipv6.to_string(), config::net::PORT_WEBSOCKET)
                            }
                        };
                        let try_bind = webserver.bind(bind_format.clone()).map_err(|error| {
                            error!("On IP ({:?}): {:?}", bind_format, error);
                            error
                        })?;
                        Ok(try_bind)
                    })
                },
            );
        web_server?.run();
        sys.run()
    }

    async fn websocket_answer(
        req: HttpRequest,
        stream: web::Payload,
        data: web::Data<Arc<Mutex<Addr<WSServerMonitor>>>>,
    ) -> Result<HttpResponse, Error> {
        trace!("new websocket answered!");
        let (addr, res) = ws::start_with_addr(MyWebSocket::new(), &req, stream)?;
        data.lock().unwrap().do_send(RegisterWSClient { addr });
        Ok(res)
    }
}

/// websocket connection is long running connection, it easier
/// to handle with an actor
struct MyWebSocket {}

impl Actor for MyWebSocket {
    type Context = ws::WebsocketContext<Self>;

    /// Method is called on actor start. We start the heartbeat process here.
    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("socket started");
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        // On system stop this may or may not run
        warn!("shutting down whole actix-system");
        // todo: a single (!) websocket disconnect shuts down the whole application!!!
        //       in a multi connection program this should be deactivated (e.g. only
        //       per button or never) ... or a certain websocket (localhost ...??) should
        //       be the "master"
        actix::System::current().stop();
    }
}
impl Handler<ServerEvent> for MyWebSocket {
    type Result = ();

    fn handle(&mut self, msg: ServerEvent, ctx: &mut Self::Context) {
        trace!("send: {}", msg.event.to_string());
        ctx.text(msg.event.to_string());
    }
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWebSocket {
    /// Handler for `ws::Message`
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        // process websocket messages
        match msg {
            Ok(good_message) => {
                trace!("hb handler: {:?}", good_message);
                match good_message {
                    ws::Message::Ping(msg) => {
                        ctx.pong(&msg);
                    }
                    ws::Message::Pong(_) => {}
                    ws::Message::Text(text) => {
                        let m = text.trim();
                        // /command
                        if m.starts_with('/') {
                            let v: Vec<&str> = m.splitn(2, ' ').collect();
                            match v[0] {
                                "/start" => {
                                    info!("ready from Browser received!");
                                }
                                _ => ctx.text(format!("!!! unknown command: {:?}", m)),
                            }
                        }
                    }
                    ws::Message::Binary(bin) => ctx.binary(bin),
                    ws::Message::Close(_) => {
                        ctx.stop();
                    }
                    ws::Message::Nop => (),
                    ws::Message::Continuation(_) => (), // todo: what's this?
                }
            }
            Err(e) => warn!("message was not good {}", e),
        }
    }
}

impl MyWebSocket {
    fn new() -> Self {
        Self {}
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    #[stable]
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
    /// TODO: consider only allowing `get_mut()` from the current
    ///       level, to remove the need to keep a mutable borrow
    ///       on the parent level. We could allow an overwrite here
    ///       instead.
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// ```
    ///
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    #[stable]
    pub fn contains_key(&self, key: &K) -> bool  {
        !self.whiteouts.contains(key)  &&
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    #[stable]
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (!self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<commit_msg>Add stability annotations<commit_after>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
#[unstable(feature = "forktable", since = "0.0.3")]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    #[stable(feature = "forktable", since = "0.0.3")]
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
    /// TODO: consider only allowing `get_mut()` from the current
    ///       level, to remove the need to keep a mutable borrow
    ///       on the parent level. We could allow an overwrite here
    ///       instead.
   #[unstable(feature = "forktable", since = "0.0.3")]
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// ```
    ///
    #[unstable(feature = "forktable", since = "0.0.3")]
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    #[stable(feature = "forktable", since = "0.0.3")]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    #[stable(feature = "forktable", since = "0.0.3")]
    pub fn contains_key(&self, key: &K) -> bool  {
        !self.whiteouts.contains(key)  &&
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    #[stable(feature = "forktable", since = "0.0.3")]
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (!self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    #[unstable(feature = "forktable", since = "0.0.3")]
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    #[stable(feature = "forktable", since = "0.0.3")]
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<|endoftext|>


<commit_before>use decoders::*;
use decoders::cfa::*;

/// All the data needed to process this raw image, including the image data itself as well
/// as all the needed metadata
#[derive(Debug, Clone)]
pub struct RawImage {
  /// camera make as encoded in the file
  pub make: String,
  /// camera model as encoded in the file
  pub model: String,
  /// make cleaned up to be consistent and short
  pub clean_make: String,
  /// model cleaned up to be consistent and short
  pub clean_model: String,
  /// width of the full image
  pub width: usize,
  /// height of the full image
  pub height: usize,
  /// number of components per pixel (1 for bayer, 3 for RGB images)
  pub cpp: usize,
  /// whitebalance coefficients encoded in the file in RGBE order
  pub wb_coeffs: [f32;4],
  /// image whitelevels in RGBE order
  pub whitelevels: [u16;4],
  /// image blacklevels in RGBE order
  pub blacklevels: [u16;4],
  /// matrix to convert XYZ to camera RGBE
  pub xyz_to_cam: [[f32;3];4],
  /// color filter array
  pub cfa: CFA,
  /// how much to crop the image to get all the usable area, order is top, right, bottom, left
  pub crops: [usize;4],
  /// orientation of the image as indicated by the image metadata
  pub orientation: Orientation,
  /// image data itself, has width*height*cpp elements
  pub data: RawImageData,
}

/// The actual image data, after decoding
#[derive(Debug, Clone)]
pub enum RawImageData {
  /// The most usual u16 output of almost all formats
  Integer(Vec<u16>),
  /// Some formats are directly encoded as f32, most notably some DNGs
  Float(Vec<f32>),
}

impl RawImage {
  #[doc(hidden)] pub fn new(camera: Camera, width: usize, height: usize, wb_coeffs: [f32;4], image: Vec<u16>) -> RawImage {
    let blacks = if camera.blackareah.1 != 0 || camera.blackareav.1 != 0 {
      let mut avg = [0 as f32; 4];
      let mut count = [0 as f32; 4];
      for row in camera.blackareah.0 .. camera.blackareah.0+camera.blackareah.1 {
        for col in 0..width {
          let color = camera.cfa.color_at(row,col);
          avg[color] += image[row*width+col] as f32;
          count[color] += 1.0;
        }
      }
      for row in 0..height {
        for col in camera.blackareav.0 .. camera.blackareav.0+camera.blackareav.1 {
          let color = camera.cfa.color_at(row,col);
          avg[color] += image[row*width+col] as f32;
          count[color] += 1.0;
        }
      }
      [(avg[0]/count[0]) as u16,
       (avg[1]/count[1]) as u16,
       (avg[2]/count[2]) as u16,
       (avg[3]/count[3]) as u16]
    } else {
      camera.blacklevels
    };

    RawImage {
      make: camera.make.clone(),
      model: camera.model.clone(),
      clean_make: camera.clean_make.clone(),
      clean_model: camera.clean_model.clone(),
      width: width,
      height: height,
      cpp: 1,
      wb_coeffs: wb_coeffs,
      data: RawImageData::Integer(image),
      blacklevels: blacks,
      whitelevels: camera.whitelevels,
      xyz_to_cam: camera.xyz_to_cam,
      cfa: camera.cfa.clone(),
      crops: camera.crops,
      orientation: camera.orientation,
    }
  }

  /// Outputs the inverted matrix that converts pixels in the camera colorspace into
  /// XYZ components. Those can then be easily used to convert to Lab or a RGB output space
  pub fn cam_to_xyz(&self) -> [[f32;4];3] {
    let (cam_to_xyz, _) = self.xyz_matrix_and_neutralwb();
    cam_to_xyz
  }

  /// Not all cameras encode a whitebalance so in those cases just using a 6500K neutral one
  /// is a good compromise
  pub fn neutralwb(&self) -> [f32;4] {
    let (_, neutralwb) = self.xyz_matrix_and_neutralwb();
    [neutralwb[0]/neutralwb[1],
     neutralwb[1]/neutralwb[1],
     neutralwb[2]/neutralwb[1],
     neutralwb[3]/neutralwb[1]]
  }

  fn xyz_matrix_and_neutralwb(&self) -> ([[f32;4];3],[f32;4]) {
    let d65_white = [0.9547,1.0,1.08883];
    let rgb_to_xyz = [
    // sRGB D65
      [ 0.412453, 0.357580, 0.180423 ],
      [ 0.212671, 0.715160, 0.072169 ],
      [ 0.019334, 0.119193, 0.950227 ],
    ];

    // Multiply RGB matrix
    let mut rgb_to_cam = [[0.0;3];4];
    for i in 0..4 {
      for j in 0..3 {
        rgb_to_cam[i][j] = 0.0;
        for k in 0..3 {
          rgb_to_cam[i][j] += self.xyz_to_cam[i][k] * rgb_to_xyz[k][j];
        }
      }
    }

    let mut neutralwb = [0 as f32; 4];
    // Normalize rgb_to_cam so that rgb_to_cam * (1,1,1) is (1,1,1,1)
    for i in 0..4 {
      let mut num = 0.0;
      for j in 0..3 {
        num += rgb_to_cam[i][j];
      }
      for j in 0..3 {
        rgb_to_cam[i][j] = if num == 0.0 {
          0.0
        }  else {
          rgb_to_cam[i][j] / num
        };
      }
      neutralwb[i] = 1.0 / num;
    }

    let cam_to_rgb = self.pseudoinverse(rgb_to_cam);
    let mut cam_to_xyz = [[0.0;4];3];
    // Multiply RGB matrix and adjust white to get a cam_to_xyz
    for i in 0..3 {
      for j in 0..4 {
        cam_to_xyz[i][j] = 0.0;
        for k in 0..3 {
          cam_to_xyz[i][j] += cam_to_rgb[k][j] * rgb_to_xyz[i][k] / d65_white[i];
        }
      }
    }

    (cam_to_xyz, neutralwb)
  }

  fn pseudoinverse(&self, inm: [[f32;3];4]) -> [[f32;4];3] {
    let mut temp: [[f32;6];3] = [[0.0; 6];3];

    for i in 0..3 {
      for j in 0..6 {
        temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
      }
      for j in 0..3 {
        for k in 0..4 {
          temp[i][j] += inm[k][i] * inm[k][j];
        }
      }
    }

    for i in 0..3 {
      let mut num = temp[i][i];
      for j in 0..6 {
        temp[i][j] /= num;
      }
      for k in 0..3 {
        if k == i { continue }
        num = temp[k][i];
        for j in 0..6 {
          temp[k][j] -= temp[i][j] * num;
        }
      }
    }

    let mut out: [[f32;4];3] = [[0.0; 4];3];

    for i in 0..4 {
      for j in 0..3 {
        out[j][i] = 0.0;
        for k in 0..3 {
          out[j][i] += temp[j][k+3] * inm[i][k];
        }
      }
    }

    out
  }

  /// Returns the CFA pattern after the crop has been applied (and thus the pattern
  /// potentially shifted)
  pub fn cropped_cfa(&self) -> CFA {
    self.cfa.shift(self.crops[3], self.crops[0])
  }

  /// Checks if the image is monochrome
  pub fn is_monochrome(&self) -> bool {
    self.cpp == 1 && !self.cfa.is_valid()
  }
}
<commit_msg>Simplify image matrix/pseudowb calculations<commit_after>use decoders::*;
use decoders::cfa::*;

/// All the data needed to process this raw image, including the image data itself as well
/// as all the needed metadata
#[derive(Debug, Clone)]
pub struct RawImage {
  /// camera make as encoded in the file
  pub make: String,
  /// camera model as encoded in the file
  pub model: String,
  /// make cleaned up to be consistent and short
  pub clean_make: String,
  /// model cleaned up to be consistent and short
  pub clean_model: String,
  /// width of the full image
  pub width: usize,
  /// height of the full image
  pub height: usize,
  /// number of components per pixel (1 for bayer, 3 for RGB images)
  pub cpp: usize,
  /// whitebalance coefficients encoded in the file in RGBE order
  pub wb_coeffs: [f32;4],
  /// image whitelevels in RGBE order
  pub whitelevels: [u16;4],
  /// image blacklevels in RGBE order
  pub blacklevels: [u16;4],
  /// matrix to convert XYZ to camera RGBE
  pub xyz_to_cam: [[f32;3];4],
  /// color filter array
  pub cfa: CFA,
  /// how much to crop the image to get all the usable area, order is top, right, bottom, left
  pub crops: [usize;4],
  /// orientation of the image as indicated by the image metadata
  pub orientation: Orientation,
  /// image data itself, has width*height*cpp elements
  pub data: RawImageData,
}

/// The actual image data, after decoding
#[derive(Debug, Clone)]
pub enum RawImageData {
  /// The most usual u16 output of almost all formats
  Integer(Vec<u16>),
  /// Some formats are directly encoded as f32, most notably some DNGs
  Float(Vec<f32>),
}

impl RawImage {
  #[doc(hidden)] pub fn new(camera: Camera, width: usize, height: usize, wb_coeffs: [f32;4], image: Vec<u16>) -> RawImage {
    let blacks = if camera.blackareah.1 != 0 || camera.blackareav.1 != 0 {
      let mut avg = [0 as f32; 4];
      let mut count = [0 as f32; 4];
      for row in camera.blackareah.0 .. camera.blackareah.0+camera.blackareah.1 {
        for col in 0..width {
          let color = camera.cfa.color_at(row,col);
          avg[color] += image[row*width+col] as f32;
          count[color] += 1.0;
        }
      }
      for row in 0..height {
        for col in camera.blackareav.0 .. camera.blackareav.0+camera.blackareav.1 {
          let color = camera.cfa.color_at(row,col);
          avg[color] += image[row*width+col] as f32;
          count[color] += 1.0;
        }
      }
      [(avg[0]/count[0]) as u16,
       (avg[1]/count[1]) as u16,
       (avg[2]/count[2]) as u16,
       (avg[3]/count[3]) as u16]
    } else {
      camera.blacklevels
    };

    RawImage {
      make: camera.make.clone(),
      model: camera.model.clone(),
      clean_make: camera.clean_make.clone(),
      clean_model: camera.clean_model.clone(),
      width: width,
      height: height,
      cpp: 1,
      wb_coeffs: wb_coeffs,
      data: RawImageData::Integer(image),
      blacklevels: blacks,
      whitelevels: camera.whitelevels,
      xyz_to_cam: camera.xyz_to_cam,
      cfa: camera.cfa.clone(),
      crops: camera.crops,
      orientation: camera.orientation,
    }
  }

  /// Outputs the inverted matrix that converts pixels in the camera colorspace into
  /// XYZ components.
  pub fn cam_to_xyz(&self) -> [[f32;4];3] {
    self.pseudoinverse(self.xyz_to_cam)
  }

  /// Outputs the inverted matrix that converts pixels in the camera colorspace into
  /// XYZ components normalized to be easily used to convert to Lab or a RGB output space
  pub fn cam_to_xyz_normalized(&self) -> [[f32;4];3] {
    let mut xyz_to_cam = self.xyz_to_cam;
    // Normalize xyz_to_cam so that xyz_to_cam * (1,1,1) is (1,1,1,1)
    for i in 0..4 {
      let mut num = 0.0;
      for j in 0..3 {
        num += xyz_to_cam[i][j];
      }
      for j in 0..3 {
        xyz_to_cam[i][j] = if num == 0.0 {
          0.0
        }  else {
          xyz_to_cam[i][j] / num
        };
      }
    }

    self.pseudoinverse(xyz_to_cam)
  }

  /// Not all cameras encode a whitebalance so in those cases just using a 6500K neutral one
  /// is a good compromise
  pub fn neutralwb(&self) -> [f32;4] {
    let rgb_to_xyz = [
    // sRGB D65
      [ 0.412453, 0.357580, 0.180423 ],
      [ 0.212671, 0.715160, 0.072169 ],
      [ 0.019334, 0.119193, 0.950227 ],
    ];

    // Multiply RGB matrix
    let mut rgb_to_cam = [[0.0;3];4];
    for i in 0..4 {
      for j in 0..3 {
        rgb_to_cam[i][j] = 0.0;
        for k in 0..3 {
          rgb_to_cam[i][j] += self.xyz_to_cam[i][k] * rgb_to_xyz[k][j];
        }
      }
    }

    let mut neutralwb = [0 as f32; 4];
    for i in 0..4 {
      let mut num = 0.0;
      for j in 0..3 {
        num += rgb_to_cam[i][j];
      }
      neutralwb[i] = 1.0 / num;
    }

    [neutralwb[0]/neutralwb[1],
     neutralwb[1]/neutralwb[1],
     neutralwb[2]/neutralwb[1],
     neutralwb[3]/neutralwb[1]]
  }

  fn pseudoinverse(&self, inm: [[f32;3];4]) -> [[f32;4];3] {
    let mut temp: [[f32;6];3] = [[0.0; 6];3];

    for i in 0..3 {
      for j in 0..6 {
        temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
      }
      for j in 0..3 {
        for k in 0..4 {
          temp[i][j] += inm[k][i] * inm[k][j];
        }
      }
    }

    for i in 0..3 {
      let mut num = temp[i][i];
      for j in 0..6 {
        temp[i][j] /= num;
      }
      for k in 0..3 {
        if k == i { continue }
        num = temp[k][i];
        for j in 0..6 {
          temp[k][j] -= temp[i][j] * num;
        }
      }
    }

    let mut out: [[f32;4];3] = [[0.0; 4];3];

    for i in 0..4 {
      for j in 0..3 {
        out[j][i] = 0.0;
        for k in 0..3 {
          out[j][i] += temp[j][k+3] * inm[i][k];
        }
      }
    }

    out
  }

  /// Returns the CFA pattern after the crop has been applied (and thus the pattern
  /// potentially shifted)
  pub fn cropped_cfa(&self) -> CFA {
    self.cfa.shift(self.crops[3], self.crops[0])
  }

  /// Checks if the image is monochrome
  pub fn is_monochrome(&self) -> bool {
    self.cpp == 1 && !self.cfa.is_valid()
  }
}
<|endoftext|>