<commit_before>#[macro_use]
extern crate jsonapi;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use jsonapi::array::JsonApiArray;
use jsonapi::model::*;

mod helper;
use helper::read_json_file;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Author {
    id: String,
    name: String,
    books: Vec<Book>,
}
jsonapi_model!(Author; "authors"; has many books);

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Book {
    id: String,
    title: String,
    first_chapter: Chapter,
    chapters: Vec<Chapter>
}
jsonapi_model!(Book; "books"; has one first_chapter; has many chapters);

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Chapter {
    id: String,
    title: String,
    ordering: i32,
}
jsonapi_model!(Chapter; "chapters");

#[test]
fn to_jsonapi_document_and_back() {
    let book = Book {
        id: "1".into(),
        title: "The Fellowship of the Ring".into(),
        first_chapter: Chapter { id: "1".into(), title: "A Long-expected Party".into(), ordering: 1 },
        chapters: vec![
            Chapter { id: "1".into(), title: "A Long-expected Party".into(), ordering: 1 },
            Chapter { id: "2".into(), title: "The Shadow of the Past".into(), ordering: 2 },
            Chapter { id: "3".into(), title: "Three is Company".into(), ordering: 3 }
        ],
    };

    let doc = book.to_jsonapi_document();
    let json = serde_json::to_string(&doc).unwrap();
    let book_doc: JsonApiDocument = serde_json::from_str(&json)
        .expect("Book JsonApiDocument should be created from the book json");
    let book_again = Book::from_jsonapi_document(&book_doc)
        .expect("Book should be generated from the book_doc");

    assert_eq!(book, book_again);
}

#[test]
fn numeric_id() {
    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    struct NumericChapter {
        id: i32,
        title: String,
    }
    jsonapi_model!(NumericChapter; "numeric_chapter");

    let chapter = NumericChapter {
        id: 24,
        title: "The Riders of Rohan".into(),
    };

    let (res, _) = chapter.to_jsonapi_resource();
    assert_eq!(res.id, "24".to_string());

    let doc = chapter.to_jsonapi_document();
    assert!(doc.is_valid());
    assert_eq!(doc.data, Some(PrimaryData::Single(Box::new(res))));

    let json = serde_json::to_string(&doc).unwrap();
    let _num_doc: JsonApiDocument = serde_json::from_str(&json)
        .expect("NumericChapter JsonApiDocument should be created from the chapter json");
}

#[test]
fn test_vec_to_jsonapi_document() {
    let chapters = vec![
        Chapter {
            id: "45".into(),
            title: "The Passing of the Grey Company".into(),
            ordering: 2,
        },
        Chapter {
            id: "46".into(),
            title: "The Muster of Rohan".into(),
            ordering: 3,
        },
    ];

    let doc = vec_to_jsonapi_document(chapters);
    assert!(doc.is_valid());
}

#[test]
fn from_jsonapi_document() {
    let json = ::read_json_file("data/author_tolkien.json");

    let author_doc: JsonApiDocument = serde_json::from_str(&json)
        .expect("Author JsonApiDocument should be created from the author json");
    let author = Author::from_jsonapi_document(&author_doc)
        .expect("Author should be generated from the author_doc");

    let doc_again = author.to_jsonapi_document();
    assert!(doc_again.is_valid());
}
<commit_msg>refactor: Fixes tests/model_test with recent changes<commit_after>#[macro_use]
extern crate jsonapi;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use jsonapi::array::JsonApiArray;
use jsonapi::model::*;

mod helper;
use helper::read_json_file;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Author {
    id: String,
    name: String,
    books: Vec<Book>,
}
jsonapi_model!(Author; "authors"; has many books);

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Book {
    id: String,
    title: String,
    first_chapter: Chapter,
    chapters: Vec<Chapter>
}
jsonapi_model!(Book; "books"; has one first_chapter; has many chapters);

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Chapter {
    id: String,
    title: String,
    ordering: i32,
}
jsonapi_model!(Chapter; "chapters");

#[test]
fn to_jsonapi_document_and_back() {
    let book = Book {
        id: "1".into(),
        title: "The Fellowship of the Ring".into(),
        first_chapter: Chapter { id: "1".into(), title: "A Long-expected Party".into(), ordering: 1 },
        chapters: vec![
            Chapter { id: "1".into(), title: "A Long-expected Party".into(), ordering: 1 },
            Chapter { id: "2".into(), title: "The Shadow of the Past".into(), ordering: 2 },
            Chapter { id: "3".into(), title: "Three is Company".into(), ordering: 3 }
        ],
    };

    let doc = book.to_jsonapi_document();
    let json = serde_json::to_string(&doc).unwrap();
    let book_doc: DocumentData = serde_json::from_str(&json)
        .expect("Book DocumentData should be created from the book json");
    let book_again = Book::from_jsonapi_document(&book_doc)
        .expect("Book should be generated from the book_doc");

    assert_eq!(book, book_again);
}

#[test]
fn numeric_id() {
    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    struct NumericChapter {
        id: i32,
        title: String,
    }
    jsonapi_model!(NumericChapter; "numeric_chapter");

    let chapter = NumericChapter {
        id: 24,
        title: "The Riders of Rohan".into(),
    };

    let (res, _) = chapter.to_jsonapi_resource();
    assert_eq!(res.id, "24".to_string());

    let doc = chapter.to_jsonapi_document();
    assert!(doc.is_valid());
    match &doc {
        JsonApiDocument::Error(_) => assert!(false),
        JsonApiDocument::Data(x) => {
            assert_eq!(x.data, Some(PrimaryData::Single(Box::new(res))));
        }
    }

    let json = serde_json::to_string(&doc).unwrap();
    let _num_doc: JsonApiDocument = serde_json::from_str(&json)
        .expect("NumericChapter JsonApiDocument should be created from the chapter json");
}

#[test]
fn test_vec_to_jsonapi_document() {
    let chapters = vec![
        Chapter {
            id: "45".into(),
            title: "The Passing of the Grey Company".into(),
            ordering: 2,
        },
        Chapter {
            id: "46".into(),
            title: "The Muster of Rohan".into(),
            ordering: 3,
        },
    ];

    let doc = vec_to_jsonapi_document(chapters);
    assert!(doc.is_valid());
}

#[test]
fn from_jsonapi_document() {
    let json = ::read_json_file("data/author_tolkien.json");

    // TODO - is this the right thing that we want to test? Shold this cast into a JsonApiDocument
    // and detect if this was a data or an error?
    // Not sure that we want to immediately cast this into a "data" when we don't know if this isi
    // valid test file - it could be an error document for all we know... (that is equally valid)
    let author_doc: JsonApiDocument = serde_json::from_str(&json)
        .expect("Author DocumentData should be created from the author json");

    // This assumes that the fixture we're using is a "valid" document with data
    match author_doc {
        JsonApiDocument::Error(_) => assert!(false),
        JsonApiDocument::Data(doc) => {
            let author = Author::from_jsonapi_document(&doc)
                .expect("Author should be generated from the author_doc");

            let doc_again = author.to_jsonapi_document();
            assert!(doc_again.is_valid());
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Collapse nom usage into self<commit_after><|endoftext|>


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

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Clone)]
pub struct ConnectedComponent {
    counter: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.counter == other.counter
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.counter.hash(state);
    }
}

pub struct Graph {
    pub size: usize,
    pub neighbours: HashMap<ConnectedComponent, HashSet<ConnectedComponent>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1 ) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> = components_and_neighbours
        .iter()
        .flat_map(|(component, _)| {
            component.cells
            .iter()
            .map(|cell| (cell.clone(), component.clone()))
            .collect::<Vec<(Position, ConnectedComponent)>>()
        })
        .collect();

        let mut neighbours:  HashMap<ConnectedComponent, HashSet<ConnectedComponent>> = HashMap::new();

        for (component, neighbour_cells) in components_and_neighbours {
            let mut neighbour_components: HashSet<ConnectedComponent> = HashSet::new();

            for cell in neighbour_cells {
                let position = Position{column: cell % grid.number_of_columns, row: cell / grid.number_of_columns};
                neighbour_components.insert(map_cell_to_component[&position].clone());
            }

            neighbours.insert(component, neighbour_components);
        }

        Self {
             size: grid.number_of_columns,
             neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &component.cells {
                cells[position.column + position.row * columns] = component.colour;
            }
        }

        Grid { number_of_rows: rows, number_of_columns: columns, cells, }
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red; 4]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }
}
<commit_msg>Add helper method for finding the component a cell belongs to<commit_after>use std::hash::Hash;
use std::collections::{HashMap, HashSet, VecDeque};

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Clone)]
pub struct ConnectedComponent {
    counter: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.counter == other.counter
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.counter.hash(state);
    }
}

pub struct Graph {
    pub size: usize,
    pub neighbours: HashMap<ConnectedComponent, HashSet<ConnectedComponent>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1 ) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> = components_and_neighbours
        .iter()
        .flat_map(|(component, _)| {
            component.cells
            .iter()
            .map(|cell| (cell.clone(), component.clone()))
            .collect::<Vec<(Position, ConnectedComponent)>>()
        })
        .collect();

        let mut neighbours:  HashMap<ConnectedComponent, HashSet<ConnectedComponent>> = HashMap::new();

        for (component, neighbour_cells) in components_and_neighbours {
            let mut neighbour_components: HashSet<ConnectedComponent> = HashSet::new();

            for cell in neighbour_cells {
                let position = Position{column: cell % grid.number_of_columns, row: cell / grid.number_of_columns};
                neighbour_components.insert(map_cell_to_component[&position].clone());
            }

            neighbours.insert(component, neighbour_components);
        }

        Self {
             size: grid.number_of_columns,
             neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &component.cells {
                cells[position.column + position.row * columns] = component.colour;
            }
        }

        Grid { number_of_rows: rows, number_of_columns: columns, cells, }
    }

    pub fn find_component(&self, position: Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if component.cells.contains(&position) {
                return component
            }
        }

        unreachable!()
    }
}

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

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red; 4]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid{
            number_of_columns: 2,
             number_of_rows: 2,
             cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow]
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }
}
<|endoftext|>


<commit_before>//! Tests for loading errors.

#![cfg(test)]

use cairo;
use librsvg::{CairoRenderer, Loader, LoadingError, RenderingError};

use crate::utils::fixture_path;

#[test]
fn too_many_elements() {
    let name = "tests/fixtures/errors/515-too-many-elements.svgz";

    assert!(matches!(
        Loader::new().read_path(fixture_path(name)),
        Err(LoadingError::XmlParseError(_))
    ));
}

fn rendering_instancing_limit(name: &str) {
    let handle = Loader::new()
        .read_path(fixture_path(name))
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 500).unwrap();
    let cr = cairo::Context::new(&surface);

    // Note that at least 515-patttern-billion-laughs.svg requires a viewport of this size
    // or bigger; a smaller one causes the recursive patterns to get so small that they
    // are culled out, and so the document doesn't reach the instancing limit.
    assert!(matches!(
        CairoRenderer::new(&handle).render_document(
            &cr,
            &cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 500.0,
                height: 500.0,
            },
        ),
        Err(RenderingError::InstancingLimit)
    ));
}

#[test]
fn instancing_limit1() {
    rendering_instancing_limit("tests/fixtures/errors/323-nested-use.svg");
}

#[test]
fn instancing_limit2() {
    rendering_instancing_limit("tests/fixtures/errors/515-pattern-billion-laughs.svg");
}
<commit_msg>Ignore the errors tests by default<commit_after>//! Tests for loading errors.
//!
//! Note that all the tests in this module are `#[ignore]`.  This is because they
//! take a much longer time to run than normal tests, as they depend upon actually
//! hitting the limits in librsvg for the number of loaded elements, or the number
//! of referenced elements during rendering.
//!
//! There is a *big* difference in the run-time of these tests when compiled with
//! `--release` versus `--debug`.  So, we will only run them in release-mode tests.

#![cfg(test)]

use cairo;
use librsvg::{CairoRenderer, Loader, LoadingError, RenderingError};

use crate::utils::fixture_path;

#[ignore]
#[test]
fn too_many_elements() {
    let name = "tests/fixtures/errors/515-too-many-elements.svgz";

    assert!(matches!(
        Loader::new().read_path(fixture_path(name)),
        Err(LoadingError::XmlParseError(_))
    ));
}

fn rendering_instancing_limit(name: &str) {
    let handle = Loader::new()
        .read_path(fixture_path(name))
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, 500, 500).unwrap();
    let cr = cairo::Context::new(&surface);

    // Note that at least 515-patttern-billion-laughs.svg requires a viewport of this size
    // or bigger; a smaller one causes the recursive patterns to get so small that they
    // are culled out, and so the document doesn't reach the instancing limit.
    assert!(matches!(
        CairoRenderer::new(&handle).render_document(
            &cr,
            &cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 500.0,
                height: 500.0,
            },
        ),
        Err(RenderingError::InstancingLimit)
    ));
}

#[ignore]
#[test]
fn instancing_limit1() {
    rendering_instancing_limit("tests/fixtures/errors/323-nested-use.svg");
}

#[ignore]
#[test]
fn instancing_limit2() {
    rendering_instancing_limit("tests/fixtures/errors/515-pattern-billion-laughs.svg");
}
<|endoftext|>


<commit_before>
extern crate bitcrust_lib;

extern crate byteorder;

use std::io::BufReader;
use std::fs::File;

mod blk_file;

#[test]
fn load_file1() {

    let mut store = bitcrust_lib::init();

    let fileno = 0;
    let name = format!("./data/blk{:05}.dat", fileno);
    println!("Processing {}", name);
    let f = File::open(name).unwrap();
    let mut rdr = BufReader::new(f);

    let mut blocks = 0;
    loop {
        let blk = blk_file::read_block(&mut rdr).unwrap();

        if blk.is_none() {
            break;
        }

        bitcrust_lib::add_block(&mut store, &blk.unwrap());

        blocks += 1;

        if blocks == 2 {
            break;
        }

    }

}

#[test]
#[ignore]
fn load_file_large() {

    let mut store = bitcrust_lib::init();
    let mut blocks = 0;

    for fileno in 0..99 {
        let name = format!("./data/blk{:05}.dat", fileno);
        println!("Processing {}", name);
        let f = File::open(name).unwrap();
        let mut rdr = BufReader::new(f);

        loop {
            let blk = blk_file::read_block(&mut rdr).unwrap();

            if blk.is_none() {
                break;
            }

            bitcrust_lib::add_block(&mut store, &blk.unwrap());

            blocks += 1;

            if blocks == 300000 {
                break;
            }
        }
    }

}<commit_msg>Ignore test that needs datafiles<commit_after>
extern crate bitcrust_lib;

extern crate byteorder;

use std::io::BufReader;
use std::fs::File;

mod blk_file;

#[test]
#[ignore]
fn load_file1() {

    let mut store = bitcrust_lib::init();

    let fileno = 0;
    let name = format!("./data/blk{:05}.dat", fileno);
    println!("Processing {}", name);
    let f = File::open(name).unwrap();
    let mut rdr = BufReader::new(f);

    let mut blocks = 0;
    loop {
        let blk = blk_file::read_block(&mut rdr).unwrap();

        if blk.is_none() {
            break;
        }

        bitcrust_lib::add_block(&mut store, &blk.unwrap());

        blocks += 1;

        if blocks == 2 {
            break;
        }

    }

}

#[test]
#[ignore]
fn load_file_large() {

    let mut store = bitcrust_lib::init();
    let mut blocks = 0;

    for fileno in 0..99 {
        let name = format!("./data/blk{:05}.dat", fileno);
        println!("Processing {}", name);
        let f = File::open(name).unwrap();
        let mut rdr = BufReader::new(f);

        loop {
            let blk = blk_file::read_block(&mut rdr).unwrap();

            if blk.is_none() {
                break;
            }

            bitcrust_lib::add_block(&mut store, &blk.unwrap());

            blocks += 1;

            if blocks == 300000 {
                break;
            }
        }
    }

}<|endoftext|>


<commit_before>extern crate fxbox_thinkerbell;
extern crate fxbox_taxonomy;
extern crate serde_json;

use fxbox_thinkerbell::ast::*;
use fxbox_thinkerbell::parse::*;
use fxbox_thinkerbell::values::*;
use fxbox_thinkerbell::util::*;

use fxbox_taxonomy::requests::*;

#[test]
fn test_parse_bad_field() {
    let src = "{
      \"requirements\": [],
      \"allocations\": [],
      \"rules\": []
    }".to_owned();

    let result = Parser::parse(src);
    match result {
        Err(serde_json::error::Error::SyntaxError(serde_json::error::ErrorCode::UnknownField(field), _, _)) => {
            assert!(field == "requirements".to_owned() || field == "allocations".to_owned())
        },
        _ => assert!(false)
    };
}

#[test]
fn test_parse_empty() {
    let src = "{ \"rules\": []}".to_owned();
    let script = Parser::parse(src).unwrap();
    assert_eq!(script.rules.len(), 0);
}

#[test]
fn test_parse_simple_rule() {
    let src =
"{
  \"rules\": [
    {
      \"execute\": [],
      \"conditions\": [
      ]
    }
  ]
}".to_owned();
    Parser::parse(src).unwrap();
}

<commit_msg>Fixed dependency error in a test<commit_after>extern crate fxbox_thinkerbell;
extern crate fxbox_taxonomy;
extern crate serde_json;

use fxbox_thinkerbell::parse::*;

#[test]
fn test_parse_bad_field() {
    let src = "{
      \"requirements\": [],
      \"allocations\": [],
      \"rules\": []
    }".to_owned();

    let result = Parser::parse(src);
    match result {
        Err(serde_json::error::Error::SyntaxError(serde_json::error::ErrorCode::UnknownField(field), _, _)) => {
            assert!(field == "requirements".to_owned() || field == "allocations".to_owned())
        },
        _ => assert!(false)
    };
}

#[test]
fn test_parse_empty() {
    let src = "{ \"rules\": []}".to_owned();
    let script = Parser::parse(src).unwrap();
    assert_eq!(script.rules.len(), 0);
}

#[test]
fn test_parse_simple_rule() {
    let src =
"{
  \"rules\": [
    {
      \"execute\": [],
      \"conditions\": [
      ]
    }
  ]
}".to_owned();
    Parser::parse(src).unwrap();
}

<|endoftext|>


<commit_before>// Copyright (C) 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

// Progress bars implementation. Moved into a different file so it is possible
// to make some dependencies (incidacitf) optional.

use book::{Book, Crowbar, CrowbarState};

use indicatif::{ProgressBar, ProgressStyle, MultiProgress};

use std::sync::Arc;
use std::thread;
use std::mem;

/// Store the progress bars needed for the book
pub struct Bars {
    /// Whether or not to use emoji
    pub emoji: bool,
    /// Container for the progress bars
    pub multibar: Option<Arc<MultiProgress>>,
    /// Main progress bar (actually a spinner)
    pub mainbar: Option<ProgressBar>,
    /// Secondary bar
    pub secondbar: Option<ProgressBar>,
    /// Guard for thread
    pub guard: Option<thread::JoinHandle<()>>,
    /// Spinners for each renderier
    pub spinners: Vec<ProgressBar>,
}

impl Bars {
    /// Create a new bars storage
    pub fn new() -> Bars {
        Bars {
            emoji: false,
            multibar: None,
            mainbar: None,
            secondbar: None,
            guard: None,
            spinners: vec![],
        }
    }
}

/// Return the style of a bar

impl Book {
    /// Adds a progress bar where where info should be written.
    ///
    /// See [indicatif doc](https://docs.rs/indicatif) for more information.
    pub fn private_add_progress_bar(&mut self, emoji: bool) {
        self.bars.emoji = emoji;
        let multibar = Arc::new(MultiProgress::new());
        self.bars.multibar = Some(multibar.clone());
        let b = self.bars.multibar
            .as_ref()
            .unwrap()
            .add(ProgressBar::new_spinner());
        b.enable_steady_tick(200);
        self.bars.mainbar = Some(b);
//        let sty = ProgressStyle::default_spinner()
//            .tick_chars("🕛🕐🕑🕒🕓🕔🕔🕕🕖🕗🕘🕘🕙🕚V")
//            .tick_chars("/|\\-V")
//            .template("{spinner:.dim.bold.yellow} {prefix} {wide_msg}");
        self.bar_set_style(Crowbar::Main, CrowbarState::Running);
        self.bars.guard = Some(thread::spawn(move || {
            if let Err(_) = multibar.join() {
                error!("{}", lformat!("could not display fancy UI, try running crowbook with --no-fancy"));
            }
        }));
    }

    /// Sets a finished message to the progress bar, if it is set
    pub fn bar_finish(&self, bar: Crowbar, state: CrowbarState, msg: &str) {
        self.bar_set_style(bar, state);
        let pb = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },
        };

        match bar {
            Crowbar::Second => pb.finish_and_clear(),
            _ => pb.finish_with_message(msg),
        };
    }

    /// Adds a secondary progress bar to display progress of book parsing
    pub fn add_second_bar(&mut self, msg: &str, len: u64)  {
        if let Some(ref multibar) = self.bars.multibar {
            let bar = multibar.add(ProgressBar::new(len));
            self.bar_set_style(Crowbar::Second, CrowbarState::Running);
            bar.set_message(msg);
            self.bars.secondbar = Some(bar);
        }
    }

    /// Increment second bar
    pub fn inc_second_bar(&self) {
        if let Some(ref bar) = self.bars.secondbar {
            bar.inc(1);
        }
    }

    /// Adds a spinner labeled key to the multibar, and set mainbar to "rendering"
    pub fn add_spinner_to_multibar(&mut self, key: &str) -> usize {
        if let Some(ref multibar) = self.bars.multibar {
            if let Some(ref mainbar) = self.bars.mainbar {
                mainbar.set_message(&lformat!("Rendering..."));
            }

            let bar = multibar.add(ProgressBar::new_spinner());
            bar.enable_steady_tick(200);
            bar.set_message(&lformat!("waiting..."));
            bar.set_prefix(&format!("{}:", key));
            let i = self.bars.spinners.len();
            self.bars.spinners.push(bar);
            self.bar_set_style(Crowbar::Spinner(i), CrowbarState::Running);

            i
        } else {
            0
        }
    }

    pub fn bar_set_message(&self, bar: Crowbar, msg: &str) {
        let bar = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },
        };
        bar.set_message(msg);
    }

    /// Sets the style of a  bar
    fn bar_set_style(&self, bar: Crowbar, state: CrowbarState) -> () {
        let pb = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },

        };
        let emoji = self.bars.emoji;
        let mut style = match bar {
            Crowbar::Second => ProgressStyle::default_bar(),
            _ => ProgressStyle::default_spinner()
        };

        let color = match state {
            CrowbarState::Running => "magenta",
            CrowbarState::Success => "cyan",
            CrowbarState::Error => "red",
        };
        let tick_chars = match (bar, emoji) {
            (Crowbar::Main, false)  | (Crowbar::Spinner(_), false) => "-\\|/",
            (Crowbar::Main, true) => "🕛🕐🕑🕒🕓🕔🕔🕕🕖🕗🕘🕘🕙🕚",
            (Crowbar::Spinner(_), true) => "-\\|/",
            (_, _) => ""
        };
        let end_tick = match (state, emoji) {
            (CrowbarState::Running, _) => "V",
            (CrowbarState::Success, true) => "✔",
            (CrowbarState::Error, true) => "❌",
            (CrowbarState::Success, false) => "V",
            (CrowbarState::Error, false) => "X",
        };
        match bar {
            Crowbar::Second => {
                style = style.template("{bar:40.cyan/blue} {percent:>7} {wide_msg}")
                    .progress_chars("##-");
            },
            bar => {
                style = style.tick_chars(&format!("{}{}", tick_chars, end_tick));
                match bar {
                    Crowbar::Spinner(_) => {
                        style = style
                            .template(&format!("{{spinner:.bold.{color}}} {{prefix}} {{wide_msg}}",
                                               color = color));
                    },
                    _ => {
                        style = style
                            .template(&format!("{{spinner:.bold.{color}}} {{prefix}}{{wide_msg}}",
                                               color = color));
                    },
                };
            },
        }
        pb.set_style(style);
    }
}

impl Drop for Book {
    fn drop(&mut self) {
        if let Some(ref bar) = self.bars.mainbar {
            bar.finish();
            let guard = mem::replace(&mut self.bars.guard, None);
            guard.unwrap()
                .join()
                .unwrap();
        }
    }
}
<commit_msg>Tweak a bit spinners' appearance<commit_after>// Copyright (C) 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

// Progress bars implementation. Moved into a different file so it is possible
// to make some dependencies (incidacitf) optional.

use book::{Book, Crowbar, CrowbarState};

use indicatif::{ProgressBar, ProgressStyle, MultiProgress};

use std::sync::Arc;
use std::thread;
use std::mem;

/// Store the progress bars needed for the book
pub struct Bars {
    /// Whether or not to use emoji
    pub emoji: bool,
    /// Container for the progress bars
    pub multibar: Option<Arc<MultiProgress>>,
    /// Main progress bar (actually a spinner)
    pub mainbar: Option<ProgressBar>,
    /// Secondary bar
    pub secondbar: Option<ProgressBar>,
    /// Guard for thread
    pub guard: Option<thread::JoinHandle<()>>,
    /// Spinners for each renderier
    pub spinners: Vec<ProgressBar>,
}

impl Bars {
    /// Create a new bars storage
    pub fn new() -> Bars {
        Bars {
            emoji: false,
            multibar: None,
            mainbar: None,
            secondbar: None,
            guard: None,
            spinners: vec![],
        }
    }
}

/// Return the style of a bar

impl Book {
    /// Adds a progress bar where where info should be written.
    ///
    /// See [indicatif doc](https://docs.rs/indicatif) for more information.
    pub fn private_add_progress_bar(&mut self, emoji: bool) {
        self.bars.emoji = emoji;
        let multibar = Arc::new(MultiProgress::new());
        self.bars.multibar = Some(multibar.clone());
        let b = self.bars.multibar
            .as_ref()
            .unwrap()
            .add(ProgressBar::new_spinner());
        b.enable_steady_tick(200);
        self.bars.mainbar = Some(b);
//        let sty = ProgressStyle::default_spinner()
//            .tick_chars("🕛🕐🕑🕒🕓🕔🕔🕕🕖🕗🕘🕘🕙🕚V")
//            .tick_chars("/|\\-V")
//            .template("{spinner:.dim.bold.yellow} {prefix} {wide_msg}");
        self.bar_set_style(Crowbar::Main, CrowbarState::Running);
        self.bars.guard = Some(thread::spawn(move || {
            if let Err(_) = multibar.join() {
                error!("{}", lformat!("could not display fancy UI, try running crowbook with --no-fancy"));
            }
        }));
    }

    /// Sets a finished message to the progress bar, if it is set
    pub fn bar_finish(&self, bar: Crowbar, state: CrowbarState, msg: &str) {
        self.bar_set_style(bar, state);
        let pb = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },
        };

        match bar {
            Crowbar::Second => pb.finish_and_clear(),
            _ => pb.finish_with_message(msg),
        };
    }

    /// Adds a secondary progress bar to display progress of book parsing
    pub fn add_second_bar(&mut self, msg: &str, len: u64)  {
        if let Some(ref multibar) = self.bars.multibar {
            let bar = multibar.add(ProgressBar::new(len));
            self.bar_set_style(Crowbar::Second, CrowbarState::Running);
            bar.set_message(msg);
            self.bars.secondbar = Some(bar);
        }
    }

    /// Increment second bar
    pub fn inc_second_bar(&self) {
        if let Some(ref bar) = self.bars.secondbar {
            bar.inc(1);
        }
    }

    /// Adds a spinner labeled key to the multibar, and set mainbar to "rendering"
    pub fn add_spinner_to_multibar(&mut self, key: &str) -> usize {
        if let Some(ref multibar) = self.bars.multibar {
            if let Some(ref mainbar) = self.bars.mainbar {
                mainbar.set_message(&lformat!("Rendering..."));
            }

            let bar = multibar.add(ProgressBar::new_spinner());
            bar.enable_steady_tick(200);
            bar.set_message(&lformat!("waiting..."));
            bar.set_prefix(&format!("{}:", key));
            let i = self.bars.spinners.len();
            self.bars.spinners.push(bar);
            self.bar_set_style(Crowbar::Spinner(i), CrowbarState::Running);

            i
        } else {
            0
        }
    }

    pub fn bar_set_message(&self, bar: Crowbar, msg: &str) {
        let bar = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },
        };
        bar.set_message(msg);
    }

    /// Sets the style of a  bar
    fn bar_set_style(&self, bar: Crowbar, state: CrowbarState) -> () {
        let pb = match bar {
            Crowbar::Main => if let Some(ref bar) = self.bars.mainbar { bar } else { return; },
            Crowbar::Second => if let Some(ref bar) = self.bars.secondbar { bar } else { return; },
            Crowbar::Spinner(i) => if i < self.bars.spinners.len() { &self.bars.spinners[i] } else { return; },

        };
        let emoji = self.bars.emoji;
        let mut style = match bar {
            Crowbar::Second => ProgressStyle::default_bar(),
            _ => ProgressStyle::default_spinner()
        };

        let color = match state {
            CrowbarState::Running => "yellow",
            CrowbarState::Success => "cyan",
            CrowbarState::Error => "red",
        };
        let tick_chars = match (bar, emoji) {
            (Crowbar::Main, false)  | (Crowbar::Spinner(_), false) => "-\\|/",
            (Crowbar::Main, true) => "🕛🕐🕑🕒🕓🕔🕔🕕🕖🕗🕘🕘🕙🕚",
            (Crowbar::Spinner(_), true) => "◐◓◑◒",
            (_, _) => ""
        };
        let end_tick = match (state, emoji) {
            (CrowbarState::Running, _) => "V",
            (CrowbarState::Success, true) => "✔",
            (CrowbarState::Error, true) => "❌",
            (CrowbarState::Success, false) => "V",
            (CrowbarState::Error, false) => "X",
        };
        match bar {
            Crowbar::Second => {
                style = style.template("{bar:40.cyan/blue} {percent:>7} {wide_msg}")
                    .progress_chars("##-");
            },
            bar => {
                style = style.tick_chars(&format!("{}{}", tick_chars, end_tick));
                match bar {
                    Crowbar::Spinner(_) => {
                        style = style
                            .template(&format!("{{spinner:.bold.{color}}} {{prefix}} {{wide_msg}}",
                                               color = color));
                    },
                    _ => {
                        style = style
                            .template(&format!("{{spinner:.bold.{color}}} {{prefix}}{{wide_msg}}",
                                               color = color));
                    },
                };
            },
        }
        pb.set_style(style);
    }
}

impl Drop for Book {
    fn drop(&mut self) {
        if let Some(ref bar) = self.bars.mainbar {
            bar.finish();
            let guard = mem::replace(&mut self.bars.guard, None);
            guard.unwrap()
                .join()
                .unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate rosc;

use std::net;

#[test]
fn test_parse_ip_and_port() {
    let valid_addr = "127.0.0.1:8080".to_string();
    let mut addr = rosc::utils::parse_ip_and_port(&valid_addr);
    assert!(addr.is_ok());
    let (ip, port) = addr.unwrap();
    assert_eq!(port, 8080u16);
    assert_eq!(ip, net::Ipv4Addr::new(127u8, 0u8, 0u8, 1u8));

    let bad_addr = "127..1:8080".to_string();
    addr = rosc::utils::parse_ip_and_port(&bad_addr);
    assert!(addr.is_err());

    let bad_addr_port = "192.168.0.10:99999".to_string();
    addr = rosc::utils::parse_ip_and_port(&bad_addr_port);
    assert!(addr.is_err());
}<commit_msg>Add test for `pad` function<commit_after>extern crate rosc;

use std::net;

#[test]
fn test_parse_ip_and_port() {
    let valid_addr = "127.0.0.1:8080".to_string();
    let mut addr = rosc::utils::parse_ip_and_port(&valid_addr);
    assert!(addr.is_ok());
    let (ip, port) = addr.unwrap();
    assert_eq!(port, 8080u16);
    assert_eq!(ip, net::Ipv4Addr::new(127u8, 0u8, 0u8, 1u8));

    let bad_addr = "127..1:8080".to_string();
    addr = rosc::utils::parse_ip_and_port(&bad_addr);
    assert!(addr.is_err());

    let bad_addr_port = "192.168.0.10:99999".to_string();
    addr = rosc::utils::parse_ip_and_port(&bad_addr_port);
    assert!(addr.is_err());
}

#[test]
fn test_pad() {
    assert_eq!(4, rosc::utils::pad(4));
    assert_eq!(8, rosc::utils::pad(5));
    assert_eq!(8, rosc::utils::pad(6));
    assert_eq!(8, rosc::utils::pad(7));
}<|endoftext|>


<commit_before>//! Asynchronous values.

use core::cell::Cell;
use core::marker::Unpin;
use core::pin::Pin;
use core::option::Option;
use core::ptr::NonNull;
use core::task::{Context, Poll};
use core::ops::{Drop, Generator, GeneratorState};

#[doc(inline)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future::*;

/// Wrap a generator in a future.
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
    GenFuture(x)
}

/// A wrapper around generators used to implement `Future` for `async`/`await` code.
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
struct GenFuture<T: Generator<Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
// self-referential borrows in the underlying generator.
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
    type Output = T::Return;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
        set_task_context(cx, || match gen.resume() {
            GeneratorState::Yielded(()) => Poll::Pending,
            GeneratorState::Complete(x) => Poll::Ready(x),
        })
    }
}

thread_local! {
    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
}

struct SetOnDrop(Option<NonNull<Context<'static>>>);

impl Drop for SetOnDrop {
    fn drop(&mut self) {
        TLS_CX.with(|tls_cx| {
            tls_cx.set(self.0.take());
        });
    }
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Sets the thread-local task context used by async/await futures.
pub fn set_task_context<F, R>(cx: &mut Context<'_>, f: F) -> R
where
    F: FnOnce() -> R
{
    // transmute the context's lifetime to 'static so we can store it.
    let cx = unsafe {
        core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx)
    };
    let old_cx = TLS_CX.with(|tls_cx| {
        tls_cx.replace(Some(NonNull::from(cx)))
    });
    let _reset = SetOnDrop(old_cx);
    f()
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Retrieves the thread-local task context used by async/await futures.
///
/// This function acquires exclusive access to the task context.
///
/// Panics if no context has been set or if the context has already been
/// retrieved by a surrounding call to get_task_context.
pub fn get_task_context<F, R>(f: F) -> R
where
    F: FnOnce(&mut Context<'_>) -> R
{
    let cx_ptr = TLS_CX.with(|tls_cx| {
        // Clear the entry so that nested `get_task_waker` calls
        // will fail or set their own value.
        tls_cx.replace(None)
    });
    let _reset = SetOnDrop(cx_ptr);

    let mut cx_ptr = cx_ptr.expect(
        "TLS Context not set. This is a rustc bug. \
        Please file an issue on https://github.com/rust-lang/rust.");

    // Safety: we've ensured exclusive access to the context by
    // removing the pointer from TLS, only to be replaced once
    // we're done with it.
    //
    // The pointer that was inserted came from an `&mut Context<'_>`,
    // so it is safe to treat as mutable.
    unsafe { f(cx_ptr.as_mut()) }
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task waker.
pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
where
    F: Future
{
    get_task_context(|cx| F::poll(f, cx))
}
<commit_msg>Remove some stack frames from `.async` calls<commit_after>//! Asynchronous values.

use core::cell::Cell;
use core::marker::Unpin;
use core::pin::Pin;
use core::option::Option;
use core::ptr::NonNull;
use core::task::{Context, Poll};
use core::ops::{Drop, Generator, GeneratorState};

#[doc(inline)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future::*;

/// Wrap a generator in a future.
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
    GenFuture(x)
}

/// A wrapper around generators used to implement `Future` for `async`/`await` code.
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
struct GenFuture<T: Generator<Yield = ()>>(T);

// We rely on the fact that async/await futures are immovable in order to create
// self-referential borrows in the underlying generator.
impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
    type Output = T::Return;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
        let _guard = unsafe { set_task_context(cx) };
        match gen.resume() {
            GeneratorState::Yielded(()) => Poll::Pending,
            GeneratorState::Complete(x) => Poll::Ready(x),
        }
    }
}

thread_local! {
    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
}

struct SetOnDrop(Option<NonNull<Context<'static>>>);

impl Drop for SetOnDrop {
    fn drop(&mut self) {
        TLS_CX.with(|tls_cx| {
            tls_cx.set(self.0.take());
        });
    }
}

// Safety: the returned guard must drop before `cx` is dropped and before
// any previous guard is dropped.
unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop {
    // transmute the context's lifetime to 'static so we can store it.
    let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx);
    let old_cx = TLS_CX.with(|tls_cx| {
        tls_cx.replace(Some(NonNull::from(cx)))
    });
    SetOnDrop(old_cx)
}

#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task waker.
pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
where
    F: Future
{
    let cx_ptr = TLS_CX.with(|tls_cx| {
        // Clear the entry so that nested `get_task_waker` calls
        // will fail or set their own value.
        tls_cx.replace(None)
    });
    let _reset = SetOnDrop(cx_ptr);

    let mut cx_ptr = cx_ptr.expect(
        "TLS Context not set. This is a rustc bug. \
        Please file an issue on https://github.com/rust-lang/rust.");

    // Safety: we've ensured exclusive access to the context by
    // removing the pointer from TLS, only to be replaced once
    // we're done with it.
    //
    // The pointer that was inserted came from an `&mut Context<'_>`,
    // so it is safe to treat as mutable.
    unsafe { F::poll(f, cx_ptr.as_mut()) }
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use std::fmt;
use std::collections::HashSet;
use ast::*;

/// An enum of errors that can occur
#[derive(Debug, Clone)]
pub enum Error {
    UndefinedName(String),
    TypeError(String),
}
impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            Error::UndefinedName(ref name) => format!("{} is undefined", name),
            Error::TypeError(ref msg) => format!("Type error: {}", msg),
        })
    }
}

/// A type allias to make type definitions shorter
pub type Result<T> = ::std::result::Result<T, Error>;

/// A mapping between names and their types
#[derive(Debug, Clone)]
pub enum Enviroment {
    Empty,
    Frame(String, TypeScheme, Box<Enviroment>),
}
impl Enviroment {
    pub fn empty() -> Enviroment {
        Enviroment::Empty
    }
    pub fn extend(&self, n: String, t: TypeScheme) -> Enviroment {
        Enviroment::Frame(n, t, Box::new(self.clone()))
    }
    pub fn lookup(&self, key: &str) -> Option<TypeScheme> {
        match *self {
            Enviroment::Empty => None,
            Enviroment::Frame(ref n, ref s, ref p) => {
                if n == key {
                    Some(s.clone())
                } else {
                    p.lookup(key)
                }
            }
        }
    }
    pub fn schemes(&self) -> Vec<TypeScheme> {
        let mut schemes = vec![];
        let mut s = self;
        loop {
            match *s {
                Enviroment::Empty => return schemes,
                Enviroment::Frame(_, ref scm, ref p) => {
                    schemes.push(scm.clone());
                    s = p;
                }
            }
        }
    }
    pub fn type_vars(&self) -> HashSet<u32> {
        let mut vars = HashSet::new();
        for scm in &self.schemes() {
            vars = vars.union(&scm.type_vars()).cloned().collect();
        }
        vars
    }
}

#[derive(Debug, Clone)]
pub struct Subst {
    prev: Option<Box<Subst>>,
    x: Option<PrimitiveType>,
    t: Option<PrimitiveType>,
}
impl Subst {
    pub fn empty() -> Subst {
        Subst {
            prev: None,
            x: None,
            t: None,
        }
    }
    pub fn extend(&self, x: PrimitiveType, t: PrimitiveType) -> Subst {
        Subst {
            prev: Some(Box::new(self.clone())),
            x: Some(x),
            t: Some(t),
        }
    }
    pub fn lookup(&self, y: &PrimitiveType) -> PrimitiveType {
        if let Some(ref prev) = self.prev {
            if self.x == Some(y.clone()) { self.t.clone().unwrap() } else {prev.lookup(y)}
        } else {
            y.clone()
        }
    }
    pub fn apply(&self, t: &PrimitiveType) -> PrimitiveType {
        match *t {
            ref tv @ PrimitiveType::Var(_) => {
                let u = self.lookup(tv);
                if *t == u { t.clone() } else { self.apply(&u) }
            },
            PrimitiveType::Fun(ref a, ref r) => PrimitiveType::Fun(Box::new(self.apply(a)), Box::new(self.apply(r))),
            PrimitiveType::Con(ref name, ref typs) => PrimitiveType::Con(name.clone(), typs.iter().map(|t| self.apply(t)).collect())
        }
    }
}

#[derive(Debug, Clone)]
pub struct TypeScheme {
    typ: PrimitiveType,
    vars: HashSet<u32>,
}
impl TypeScheme {
    pub fn new(typ: PrimitiveType, vars: HashSet<u32>) -> TypeScheme {
        TypeScheme{typ, vars}
    }
    pub fn new_instance(&self, var_gen: &mut VarGenerator) -> PrimitiveType {
        self.vars.iter().fold(Subst::empty(), |sub, var| sub.extend(PrimitiveType::Var(*var),
                                                                    var_gen.next_typevar())).apply(&self.typ)
    }
    pub fn type_vars(&self) -> HashSet<u32> {
        self.typ.type_vars().difference(&self.vars).cloned().collect()
    }
    pub fn from_type(t: &PrimitiveType, env: &Enviroment) -> TypeScheme {
        TypeScheme::new(t.clone(), t.type_vars().difference(&env.type_vars()).cloned().collect())
    }
}

fn mgu(t: &PrimitiveType, u: &PrimitiveType, s: &Subst) -> Result<Subst> {
    use ast::PrimitiveType::*;
    match (s.apply(t), s.apply(u)) {
        (Var(a), Var(b)) if a == b => Ok(s.clone()),
        (Var(a), _) if !u.type_vars().contains(&a) => Ok(s.extend(Var(a), u.clone())),
        (_, Var(_)) => mgu(u, t, s),
        (Fun(ref t1, ref t2), Fun(ref u1, ref u2)) => mgu(t1, u1, &mgu(t2, u2, s)?),
        (Con(ref n1, ref ts), Con(ref n2, ref us)) if n1 == n2 => {
            Ok(ts.iter().zip(us).fold(s.clone(), |ref acc, (ref a, ref b)| mgu(a, b, acc).unwrap())) // FIXME
        },
        (ref a, ref b) => Err(Error::TypeError(format!("cannot unify {} with {}", a, b)))
    }
}

fn tp(exp: &Expr, t: &PrimitiveType, env: &Enviroment, s: &Subst, var_gen: &mut VarGenerator) -> Result<Subst> {
    match *exp {
        Expr::Var(ref n) => {
            if let Some(scm) = env.lookup(n) {
                mgu(&scm.new_instance(var_gen), t, s)
            } else {
                Err(Error::UndefinedName(format!("{} is undefined!", n)))
            }
        },
        Expr::Fun(ref arg, ref body) => {
            let a = var_gen.next_typevar();
            let b = var_gen.next_typevar();
            let s1 = mgu(t, &PrimitiveType::Fun(Box::new(a.clone()), Box::new(b.clone())), s)?;
            let env1 = env.extend(arg.clone(), TypeScheme::new(a.clone(), HashSet::new()));
            tp(body, &b, &env1, &s1, var_gen)
        },
        Expr::App(ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let s1 = tp(e1, &PrimitiveType::Fun(Box::new(a.clone()), Box::new(t.clone())), env, s, var_gen)?;
            tp(e2, &a, env, &s1, var_gen)
        },
        Expr::Let(ref x, ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let s1 = tp(e1, &a.clone(), env, s, var_gen)?;
            let env2 = env.extend(x.clone(), TypeScheme::from_type(&s1.apply(&a), env));
            tp(e2, t, &env2, &s1, var_gen)
        },
        Expr::LetRec(ref x, ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let env1 = env.extend(x.clone(), TypeScheme::from_type(&a, env));
            let s1 = tp(e1, &a.clone(), &env1, s, var_gen)?;
            let env2 = env.extend(x.clone(), TypeScheme::from_type(&s1.apply(&a), env));
            tp(e2, t, &env2, &s1, var_gen)
        },
        Expr::Num(_) => mgu(t, &int_type(), s),
        Expr::Bool(_) => mgu(t, &bool_type(), s),
        Expr::BinOp(ref l, ref op, ref r) => {
            let (expected_l_type, op_type, expected_r_type) = match *op {
                Op::Add | Op::Sub | Op::Div | Op::Mul => (int_type(), int_type(), int_type()),
                Op::And | Op::Or => (bool_type(), bool_type(), bool_type()),
                Op::Lt | Op::Gt | Op::Equal => {
                    let a = var_gen.next_typevar();
                    (a.clone(), bool_type(), a.clone())
                },
            };
            let s1 = tp(l, &expected_l_type, env, s, var_gen)?;
            let s2 = tp(r, &expected_r_type, env, &s1, var_gen)?;
            mgu(t, &op_type, &s2)
        },
        Expr::If(ref pred, ref then, ref otherwise) => {
            let s1 = tp(pred, &bool_type(), env, s, var_gen)?;
            let s2 = tp(then, t, env, &s1, var_gen)?;
            tp(otherwise, t, env, &s2, var_gen)
        }
    }
}

pub fn type_of(expr: &Expr, env: &Enviroment, var_gen: &mut VarGenerator) -> Result<PrimitiveType> {
    let a = var_gen.next_typevar();
    let s = tp(expr, &a, env, &Subst::empty(), var_gen)?;
    Ok(s.apply(&a))
}

pub fn top_level_env(var_gen: &mut VarGenerator) -> Enviroment {
    let a = var_gen.next_typevar();
    let abstract_list = list_type(a);
    let env = Enviroment::Empty;
    let env = env.extend("nil".to_owned(), TypeScheme::from_type(&abstract_list.clone(), &env));
    let a = var_gen.next_typevar();
    let pair = PrimitiveType::Fun(Box::new(a.clone()), Box::new(PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(list_type(a)))));
    let env = env.extend("pair".to_owned(), TypeScheme::from_type(&pair, &env));
    let a = var_gen.next_typevar();
    let first = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(a.clone()));
    let env = env.extend("first".to_owned(), TypeScheme::from_type(&first, &env));
    let a = var_gen.next_typevar();
    let rest = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(list_type(a.clone())));
    let env = env.extend("rest".to_owned(), TypeScheme::from_type(&rest, &env));
    let a = var_gen.next_typevar();
    let is_nil = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(bool_type()));
    let env = env.extend("is_nil".to_owned(), TypeScheme::from_type(&is_nil, &env));
    env
}

pub fn int_type() -> PrimitiveType {
    PrimitiveType::Con("int".to_owned(), vec![])
}
pub fn bool_type() -> PrimitiveType {
    PrimitiveType::Con("bool".to_owned(), vec![])
}
pub fn list_type(t: PrimitiveType) -> PrimitiveType {
    PrimitiveType::Con("List".to_owned(), vec![t])
}

#[derive(Debug, Clone)]
pub struct VarGenerator {
    next_var: u32
}
impl VarGenerator {
    pub fn new() -> VarGenerator {
        VarGenerator { next_var: 0 }
    }
    pub fn next_typevar(&mut self) -> PrimitiveType {
        self.next_var += 1;
        PrimitiveType::Var(self.next_var)
    }
}<commit_msg>Fix #3 Now it gives a type error instead of an out of stack space panic<commit_after>use std::fmt::Display;
use std::fmt;
use std::collections::HashSet;
use ast::*;

/// An enum of errors that can occur
#[derive(Debug, Clone)]
pub enum Error {
    UndefinedName(String),
    TypeError(String),
}
impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            Error::UndefinedName(ref name) => format!("{} is undefined", name),
            Error::TypeError(ref msg) => format!("Type error: {}", msg),
        })
    }
}

/// A type allias to make type definitions shorter
pub type Result<T> = ::std::result::Result<T, Error>;

/// A mapping between names and their types
#[derive(Debug, Clone)]
pub enum Enviroment {
    Empty,
    Frame(String, TypeScheme, Box<Enviroment>),
}
impl Enviroment {
    pub fn empty() -> Enviroment {
        Enviroment::Empty
    }
    pub fn extend(&self, n: String, t: TypeScheme) -> Enviroment {
        Enviroment::Frame(n, t, Box::new(self.clone()))
    }
    pub fn lookup(&self, key: &str) -> Option<TypeScheme> {
        match *self {
            Enviroment::Empty => None,
            Enviroment::Frame(ref n, ref s, ref p) => {
                if n == key {
                    Some(s.clone())
                } else {
                    p.lookup(key)
                }
            }
        }
    }
    pub fn schemes(&self) -> Vec<TypeScheme> {
        let mut schemes = vec![];
        let mut s = self;
        loop {
            match *s {
                Enviroment::Empty => return schemes,
                Enviroment::Frame(_, ref scm, ref p) => {
                    schemes.push(scm.clone());
                    s = p;
                }
            }
        }
    }
    pub fn type_vars(&self) -> HashSet<u32> {
        let mut vars = HashSet::new();
        for scm in &self.schemes() {
            vars = vars.union(&scm.type_vars()).cloned().collect();
        }
        vars
    }
}

#[derive(Debug, Clone)]
pub struct Subst {
    prev: Option<Box<Subst>>,
    x: Option<PrimitiveType>,
    t: Option<PrimitiveType>,
}
impl Subst {
    pub fn empty() -> Subst {
        Subst {
            prev: None,
            x: None,
            t: None,
        }
    }
    pub fn extend(&self, x: PrimitiveType, t: PrimitiveType) -> Subst {
        Subst {
            prev: Some(Box::new(self.clone())),
            x: Some(x),
            t: Some(t),
        }
    }
    pub fn lookup(&self, y: &PrimitiveType) -> PrimitiveType {
        if let Some(ref prev) = self.prev {
            if self.x == Some(y.clone()) { self.t.clone().unwrap() } else {prev.lookup(y)}
        } else {
            y.clone()
        }
    }
    pub fn apply(&self, t: &PrimitiveType) -> PrimitiveType {
        match *t {
            ref tv @ PrimitiveType::Var(_) => {
                let u = self.lookup(tv);
                if *t == u { t.clone() } else { self.apply(&u) }
            },
            PrimitiveType::Fun(ref a, ref r) => PrimitiveType::Fun(Box::new(self.apply(a)), Box::new(self.apply(r))),
            PrimitiveType::Con(ref name, ref typs) => PrimitiveType::Con(name.clone(), typs.iter().map(|t| self.apply(t)).collect())
        }
    }
}

#[derive(Debug, Clone)]
pub struct TypeScheme {
    typ: PrimitiveType,
    vars: HashSet<u32>,
}
impl TypeScheme {
    pub fn new(typ: PrimitiveType, vars: HashSet<u32>) -> TypeScheme {
        TypeScheme{typ, vars}
    }
    pub fn new_instance(&self, var_gen: &mut VarGenerator) -> PrimitiveType {
        self.vars.iter().fold(Subst::empty(), |sub, var| sub.extend(PrimitiveType::Var(*var),
                                                                    var_gen.next_typevar())).apply(&self.typ)
    }
    pub fn type_vars(&self) -> HashSet<u32> {
        self.typ.type_vars().difference(&self.vars).cloned().collect()
    }
    pub fn from_type(t: &PrimitiveType, env: &Enviroment) -> TypeScheme {
        TypeScheme::new(t.clone(), t.type_vars().difference(&env.type_vars()).cloned().collect())
    }
}

fn mgu(t: &PrimitiveType, u: &PrimitiveType, s: &Subst) -> Result<Subst> {
    use ast::PrimitiveType::*;
    let (w, r) = (s.apply(t), s.apply(u));
    match (w, r.clone()) {
        (Var(a), Var(b)) if a == b => Ok(s.clone()),
        (Var(a), _) if !r.type_vars().contains(&a) => Ok(s.extend(Var(a), u.clone())),
        (_, Var(_)) => mgu(u, t, s),
        (Fun(ref t1, ref t2), Fun(ref u1, ref u2)) => mgu(t1, u1, &mgu(t2, u2, s)?),
        (Con(ref n1, ref ts), Con(ref n2, ref us)) if n1 == n2 => {
            Ok(ts.iter().zip(us).fold(s.clone(), |ref acc, (ref a, ref b)| mgu(a, b, acc).unwrap())) // FIXME
        },
        (ref a, ref b) => Err(Error::TypeError(format!("cannot unify {} with {}", a, b)))
    }
}

fn tp(exp: &Expr, t: &PrimitiveType, env: &Enviroment, s: &Subst, var_gen: &mut VarGenerator) -> Result<Subst> {
    match *exp {
        Expr::Var(ref n) => {
            if let Some(scm) = env.lookup(n) {
                mgu(&scm.new_instance(var_gen), t, s)
            } else {
                Err(Error::UndefinedName(format!("{} is undefined!", n)))
            }
        },
        Expr::Fun(ref arg, ref body) => {
            let a = var_gen.next_typevar();
            let b = var_gen.next_typevar();
            let s1 = mgu(t, &PrimitiveType::Fun(Box::new(a.clone()), Box::new(b.clone())), s)?;
            let env1 = env.extend(arg.clone(), TypeScheme::new(a.clone(), HashSet::new()));
            tp(body, &b, &env1, &s1, var_gen)
        },
        Expr::App(ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let s1 = tp(e1, &PrimitiveType::Fun(Box::new(a.clone()), Box::new(t.clone())), env, s, var_gen)?;
            tp(e2, &a, env, &s1, var_gen)
        },
        Expr::Let(ref x, ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let s1 = tp(e1, &a.clone(), env, s, var_gen)?;
            let env2 = env.extend(x.clone(), TypeScheme::from_type(&s1.apply(&a), env));
            tp(e2, t, &env2, &s1, var_gen)
        },
        Expr::LetRec(ref x, ref e1, ref e2) => {
            let a = var_gen.next_typevar();
            let env1 = env.extend(x.clone(), TypeScheme::from_type(&a, env));
            let s1 = tp(e1, &a.clone(), &env1, s, var_gen)?;
            let env2 = env.extend(x.clone(), TypeScheme::from_type(&s1.apply(&a), env));
            tp(e2, t, &env2, &s1, var_gen)
        },
        Expr::Num(_) => mgu(t, &int_type(), s),
        Expr::Bool(_) => mgu(t, &bool_type(), s),
        Expr::BinOp(ref l, ref op, ref r) => {
            let (expected_l_type, op_type, expected_r_type) = match *op {
                Op::Add | Op::Sub | Op::Div | Op::Mul => (int_type(), int_type(), int_type()),
                Op::And | Op::Or => (bool_type(), bool_type(), bool_type()),
                Op::Lt | Op::Gt | Op::Equal => {
                    let a = var_gen.next_typevar();
                    (a.clone(), bool_type(), a.clone())
                },
            };
            let s1 = tp(l, &expected_l_type, env, s, var_gen)?;
            let s2 = tp(r, &expected_r_type, env, &s1, var_gen)?;
            mgu(t, &op_type, &s2)
        },
        Expr::If(ref pred, ref then, ref otherwise) => {
            let s1 = tp(pred, &bool_type(), env, s, var_gen)?;
            let s2 = tp(then, t, env, &s1, var_gen)?;
            tp(otherwise, t, env, &s2, var_gen)
        }
    }
}

pub fn type_of(expr: &Expr, env: &Enviroment, var_gen: &mut VarGenerator) -> Result<PrimitiveType> {
    let a = var_gen.next_typevar();
    let s = tp(expr, &a, env, &Subst::empty(), var_gen)?;
    Ok(s.apply(&a))
}

pub fn top_level_env(var_gen: &mut VarGenerator) -> Enviroment {
    let a = var_gen.next_typevar();
    let abstract_list = list_type(a);
    let env = Enviroment::Empty;
    let env = env.extend("nil".to_owned(), TypeScheme::from_type(&abstract_list.clone(), &env));
    let a = var_gen.next_typevar();
    let pair = PrimitiveType::Fun(Box::new(a.clone()), Box::new(PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(list_type(a)))));
    let env = env.extend("pair".to_owned(), TypeScheme::from_type(&pair, &env));
    let a = var_gen.next_typevar();
    let first = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(a.clone()));
    let env = env.extend("first".to_owned(), TypeScheme::from_type(&first, &env));
    let a = var_gen.next_typevar();
    let rest = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(list_type(a.clone())));
    let env = env.extend("rest".to_owned(), TypeScheme::from_type(&rest, &env));
    let a = var_gen.next_typevar();
    let is_nil = PrimitiveType::Fun(Box::new(list_type(a.clone())), Box::new(bool_type()));
    let env = env.extend("is_nil".to_owned(), TypeScheme::from_type(&is_nil, &env));
    env
}

pub fn int_type() -> PrimitiveType {
    PrimitiveType::Con("int".to_owned(), vec![])
}
pub fn bool_type() -> PrimitiveType {
    PrimitiveType::Con("bool".to_owned(), vec![])
}
pub fn list_type(t: PrimitiveType) -> PrimitiveType {
    PrimitiveType::Con("List".to_owned(), vec![t])
}

#[derive(Debug, Clone)]
pub struct VarGenerator {
    next_var: u32
}
impl VarGenerator {
    pub fn new() -> VarGenerator {
        VarGenerator { next_var: 0 }
    }
    pub fn next_typevar(&mut self) -> PrimitiveType {
        self.next_var += 1;
        PrimitiveType::Var(self.next_var)
    }
}<|endoftext|>


<commit_before>// Learning.

use term::Term;
use stroke::Stroke;
use words::{LearnWord, Words};

use std::io::Write;
use termion::color;

pub struct Learn {
    words: Words,
    term: Term,

    // How many of the words are we getting right.  TODO: Store this in the datafile instead of
    // regenerating it each time.
    ratio: f64,
}

impl Learn {
    pub fn new(words: Words, term: Term) -> Learn {
        Learn {
            words: words,
            term: term,
            ratio: 1.0,
        }
    }

    // Consume the learner, returning the wordset contained in it.
    pub fn into_words(self) -> Words {
        self.words
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.words.get_learned() {
                None => {
                    match self.words.get_unlearned() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            // Update the stastics, but only of words that have some chance to be learned.  The
            // interval reaching an hour seems like a good guess for this.
            if word.interval > 60.0 * 60.0 {
                match status {
                    Status::Stopped => break,
                    Status::Continue(true) => {
                        self.ratio = self.ratio * 0.97 + 0.03;
                    }
                    Status::Continue(false) => {
                        self.ratio = self.ratio * 0.97;
                    }
                }
            }

            // Return the word.
            self.words.push_word(word);
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &mut LearnWord) -> Status {
        let counts = self.words.get_counts();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}, Ratio {:.1}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval),
                 self.ratio * 100.0).unwrap();
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
        }
        writeln!(self.term, "\r").unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w mut LearnWord,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww mut LearnWord) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.english,
               if self.word.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user, &self.word.strokes)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.word.strokes, &self.word.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let result;
        loop {
            self.prompt();
            if self.word.strokes == self.user {
                result = Status::Continue(self.errors == 0);
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.word.strokes.len() ||
                    self.user[pos-1] != self.word.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        match result {
            Status::Continue(right) => {
                if right {
                    self.word.correct();
                } else {
                    self.word.incorrect();
                }

                writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
            }
            Status::Stopped => {
                writeln!(self.term, "\r").unwrap();
            }
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke], expected: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for (i, st) in strokes.iter().enumerate() {
        if !first {
            buf.push(b'/');
        }
        first = false;

        let correct = expected.get(i) == Some(st);
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::LightRed),
                   color::Fg(color::Black)).unwrap();
        }
        write!(&mut buf, "{}", st).unwrap();
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::Reset),
                   color::Fg(color::Reset)).unwrap();
        }
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    // Continue learning, and returns if the word is correct.
    Continue(bool),
    Stopped,
}
<commit_msg>Revert "Only update ratio on learned words"<commit_after>// Learning.

use term::Term;
use stroke::Stroke;
use words::{LearnWord, Words};

use std::io::Write;
use termion::color;

pub struct Learn {
    words: Words,
    term: Term,

    // How many of the words are we getting right.  TODO: Store this in the datafile instead of
    // regenerating it each time.
    ratio: f64,
}

impl Learn {
    pub fn new(words: Words, term: Term) -> Learn {
        Learn {
            words: words,
            term: term,
            ratio: 1.0,
        }
    }

    // Consume the learner, returning the wordset contained in it.
    pub fn into_words(self) -> Words {
        self.words
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.words.get_learned() {
                None => {
                    match self.words.get_unlearned() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            // Return the word.
            self.words.push_word(word);

            match status {
                Status::Stopped => break,
                Status::Continue(true) => {
                    self.ratio = self.ratio * 0.97 + 0.03;
                }
                Status::Continue(false) => {
                    self.ratio = self.ratio * 0.97;
                }
            }
            if status == Status::Stopped {
                break;
            }
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &mut LearnWord) -> Status {
        let counts = self.words.get_counts();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}, Ratio {:.1}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval),
                 self.ratio * 100.0).unwrap();
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
        }
        writeln!(self.term, "\r").unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w mut LearnWord,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww mut LearnWord) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.english,
               if self.word.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user, &self.word.strokes)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.word.strokes, &self.word.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let result;
        loop {
            self.prompt();
            if self.word.strokes == self.user {
                result = Status::Continue(self.errors == 0);
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.word.strokes.len() ||
                    self.user[pos-1] != self.word.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        match result {
            Status::Continue(right) => {
                if right {
                    self.word.correct();
                } else {
                    self.word.incorrect();
                }

                writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
            }
            Status::Stopped => {
                writeln!(self.term, "\r").unwrap();
            }
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke], expected: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for (i, st) in strokes.iter().enumerate() {
        if !first {
            buf.push(b'/');
        }
        first = false;

        let correct = expected.get(i) == Some(st);
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::LightRed),
                   color::Fg(color::Black)).unwrap();
        }
        write!(&mut buf, "{}", st).unwrap();
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::Reset),
                   color::Fg(color::Reset)).unwrap();
        }
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    // Continue learning, and returns if the word is correct.
    Continue(bool),
    Stopped,
}
<|endoftext|>