<commit_before>//! Use the API Documentation below to learn about the various things you can do with this crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! * The [`Turtle` struct](struct.Turtle.html) - lists of all the various drawing commands that the
//!   turtle supports
//! * The [`Drawing` struct](struct.Drawing.html) - allows you to manipulate the title, size,
//!   background and more of the drawing that you are creating
//! * The [`color` module](color/index.html) - describes the different ways to create colors and
//!   includes a list of the hundreds of predefined color names that you can use to easily set the
//!   pen, fill, and background color of your drawings
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.
//! # Unstable features
//! Some parts of this library are unstable, such as maximizing and unmaximizing the window.
//! You can explicitly opt-in to using those features with the `unstable` feature like so:
//!
//! ```bash
//! $ cargo build --features "unstable"
//! ```
//!
//! If you want to use this from inside your own crate, you will need to add this to your Cargo.toml
//! ```toml
//! [dependencies]
//! turtle = { version = "...", features = ["unstable"] }
//! ```

#![doc(html_logo_url = "https://raw.githubusercontent.com/sunjay/turtle/master/docs/assets/images/turtle-logo-512.png")]
#![cfg_attr(target_arch = "wasm32", crate_type = "cdylib")]

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

mod ipc_protocol;
mod renderer_server;
mod renderer_client;

mod turtle_window;

mod animation;
#[cfg(not(target_arch = "wasm32"))]
mod app;
mod drawing;
mod extensions;
#[cfg(not(target_arch = "wasm32"))]
mod messenger;
mod point;
mod query;
mod radians;
#[cfg(not(target_arch = "wasm32"))]
mod renderer;
mod renderer_process;
#[cfg(not(target_arch = "wasm32"))]
mod server;
mod speed;
mod state;
mod timer;
mod turtle;

pub mod color;
#[cfg(not(target_arch = "wasm32"))]
pub mod event;
#[cfg(target_arch = "wasm32")]
mod event {
    use serde::{Serialize, Deserialize};
    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub enum Event {}
}
pub mod rand;

pub use crate::color::Color;
pub use crate::drawing::{Drawing, Size};
pub use crate::event::Event;
pub use crate::point::Point;
#[cfg(target_arch = "wasm32")]
pub use renderer_process::{alloc, dealloc, dealloc_str};
pub use crate::speed::Speed;
pub use crate::turtle::{Angle, Distance, Turtle};

#[cfg(not(target_arch = "wasm32"))]
pub use crate::server::start;
#[cfg(target_arch = "wasm32")]
pub fn start() {}
<commit_msg>Deny unused must use to avoid missing Results/Futures<commit_after>//! Use the API Documentation below to learn about the various things you can do with this crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! * The [`Turtle` struct](struct.Turtle.html) - lists of all the various drawing commands that the
//!   turtle supports
//! * The [`Drawing` struct](struct.Drawing.html) - allows you to manipulate the title, size,
//!   background and more of the drawing that you are creating
//! * The [`color` module](color/index.html) - describes the different ways to create colors and
//!   includes a list of the hundreds of predefined color names that you can use to easily set the
//!   pen, fill, and background color of your drawings
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.
//! # Unstable features
//! Some parts of this library are unstable, such as maximizing and unmaximizing the window.
//! You can explicitly opt-in to using those features with the `unstable` feature like so:
//!
//! ```bash
//! $ cargo build --features "unstable"
//! ```
//!
//! If you want to use this from inside your own crate, you will need to add this to your Cargo.toml
//! ```toml
//! [dependencies]
//! turtle = { version = "...", features = ["unstable"] }
//! ```

// This warning usually signals an error and so it should be treated as such.
#![deny(unused_must_use)]

#![doc(html_logo_url = "https://raw.githubusercontent.com/sunjay/turtle/master/docs/assets/images/turtle-logo-512.png")]
#![cfg_attr(target_arch = "wasm32", crate_type = "cdylib")]

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

mod ipc_protocol;
mod renderer_server;
mod renderer_client;

mod turtle_window;

mod animation;
#[cfg(not(target_arch = "wasm32"))]
mod app;
mod drawing;
mod extensions;
#[cfg(not(target_arch = "wasm32"))]
mod messenger;
mod point;
mod query;
mod radians;
#[cfg(not(target_arch = "wasm32"))]
mod renderer;
mod renderer_process;
#[cfg(not(target_arch = "wasm32"))]
mod server;
mod speed;
mod state;
mod timer;
mod turtle;

pub mod color;
#[cfg(not(target_arch = "wasm32"))]
pub mod event;
#[cfg(target_arch = "wasm32")]
mod event {
    use serde::{Serialize, Deserialize};
    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub enum Event {}
}
pub mod rand;

pub use crate::color::Color;
pub use crate::drawing::{Drawing, Size};
pub use crate::event::Event;
pub use crate::point::Point;
#[cfg(target_arch = "wasm32")]
pub use renderer_process::{alloc, dealloc, dealloc_str};
pub use crate::speed::Speed;
pub use crate::turtle::{Angle, Distance, Turtle};

#[cfg(not(target_arch = "wasm32"))]
pub use crate::server::start;
#[cfg(target_arch = "wasm32")]
pub fn start() {}
<|endoftext|>


<commit_before>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate reqwest;
extern crate select;

use std::cmp;
use std::fmt::{self, Display, Write};
use std::io::prelude::*;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use reqwest::Url;
use select::document::Document;
use select::predicate::{Attr, Name};

pub mod errors;

use errors::*;

lazy_static! {
    /// Extracts the ingredients out of the text of a menu item.
    static ref INGREDIENTS_RE: Regex =
        Regex::new(r"Ingredients: (.*?)(?: - Serving Size.*)?\s*$").unwrap();

    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( ?/ ?(\d+\.\d+|[a-z]+))?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Menu(LinkedHashMap<String, Entry>);

/// A section of the menu.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Entry {
    /// The section header.
    pub heading: String,

    /// The food items listed under the header.
    pub items: Vec<String>,

    /// Information indicating what ingredients are in the food, including whether it's vegetarian,
    /// vegan, etc.
    pub dietary_info: Option<String>,
}

impl Display for Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "*{}*\n", self.heading)?;

        let items = if self.items.is_empty() {
            vec![String::from("Nothing today")]
        } else {
            self.items.clone()
        };

        for item in &items {
            let dietary_info = if let Some(ref info) = self.dietary_info {
                format!(" (_{}_)", info)
            } else {
                String::default()
            };

            writeln!(f, "• {}{}", item, dietary_info)?;
        }

        Ok(())
    }
}

impl Menu {
    /// Returns the entries of the menu.
    pub fn entries(&self) -> Vec<Entry> {
        self.0.values().cloned().collect()
    }

    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> Result<String> {
        let mut output = String::default();

        for entry in self.entries() {
            writeln!(output, "{}", entry).unwrap();
        }

        if output.is_empty() {
            bail!(ErrorKind::EmptyMenu);
        }

        writeln!(
            output,
            "> Made with :btb: by @anrussell. Please direct feature requests and bug reports to \
             https://github.com/euclio/nourishbot."
        ).unwrap();

        Ok(output)
    }
}

/// Retrieves and parses the menu for a given date.
pub fn retrieve_menu(date: &NaiveDate) -> Result<Menu> {
    let url = url_for_date(date);

    let mut res = reqwest::get(url.as_str()).map_err(|e| {
        ErrorKind::Network(e.to_string())
    })?;

    let body = if res.status().is_success() {
        let mut bytes = vec![];
        res.read_to_end(&mut bytes)?;
        String::from_utf8_lossy(&bytes).into_owned()
    } else {
        bail!(ErrorKind::Network(res.status().to_string()))
    };

    Ok(parse_menu(&body))
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!(
        "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.nsf\
        /weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
        monday.format("%m-%d-%Y"),
        days_from_monday + 1
    )).unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);
    let menu_node = document.find(Attr("id", "center_text")).next().unwrap();

    let mut menu = LinkedHashMap::new();
    let mut current_heading = None;

    for node in menu_node.children() {
        let text = node.text().trim().to_owned();

        if let Some("font-weight:bold;") = node.attr("style") {
            current_heading = Some(text.to_lowercase().to_title_case());
        } else {
            if let Some(ref heading) = current_heading {
                // Skip breakfast
                if heading == "Breakfast Special" {
                    continue;
                }

                // Skip nutrition and price information.
                if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
                    continue;
                }

                let entry = menu.entry(heading.clone()).or_insert_with(|| {
                    Entry {
                        heading: heading.to_owned(),
                        items: Vec::new(),
                        dietary_info: None,
                    }
                });

                if node.is(Name("div")) && !text.is_empty() {
                    entry.items.push(text);
                } else if let Some(caps) = INGREDIENTS_RE.captures(&text) {
                    entry.dietary_info = Some(caps[1].to_owned());
                }
            } else {
                println!("encountered entry without a heading");
                continue;
            }
        }
    }

    Menu(menu)
}

#[cfg(test)]
mod tests {
    use chrono::NaiveDate;
    use linked_hash_map::LinkedHashMap;

    use super::{Entry, Menu};

    #[test]
    fn parse_menu() {
        let html = r#"

CHEF'S SPECIAL PIZZA

        "#;

        let menu = super::parse_menu(html);
        let expected = {
            let mut menu = LinkedHashMap::new();
            menu.insert(
                String::from("Chef's Special Pizza"),
                Entry {
                    heading: String::from("Chef's Special Pizza"),
                    items: vec![],
                    dietary_info: None,
                },
            );
            Menu(menu)
        };

        assert_eq!(menu, expected);
    }

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(
            expected_url,
            &super::url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).to_string()
        );
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(
            expected_url,
            &super::url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).to_string()
        );

    }

    #[test]
    fn ingredients_regex() {
        use super::INGREDIENTS_RE;

        let test_cases = [
            ("Ingredients: Pork, Egg, Spicy", "Pork, Egg, Spicy"),
            (
                "Ingredients: Vegetarian - Contains Wheat, Dairy",
                "Vegetarian - Contains Wheat, Dairy",
            ),
            ("Ingredients: Vegan - Serving Size 12oz", "Vegan"),
        ];

        for &(text, ingredients) in &test_cases {
            let capture = INGREDIENTS_RE.captures(text).unwrap().get(1).unwrap();
            assert_eq!(capture.as_str(), ingredients);
        }
    }

    #[test]
    fn price_regex() {
        use super::PRICE_RE;

        let patterns = ["7.50", "0.25/oz", "2.15 / 2.65"];

        for pattern in &patterns {
            assert!(PRICE_RE.is_match(pattern), pattern.clone());
        }
    }
}
<commit_msg>do not print footer twice<commit_after>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate reqwest;
extern crate select;

use std::cmp;
use std::fmt::{self, Display, Write};
use std::io::prelude::*;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use reqwest::Url;
use select::document::Document;
use select::predicate::{Attr, Name};

pub mod errors;

use errors::*;

lazy_static! {
    /// Extracts the ingredients out of the text of a menu item.
    static ref INGREDIENTS_RE: Regex =
        Regex::new(r"Ingredients: (.*?)(?: - Serving Size.*)?\s*$").unwrap();

    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( ?/ ?(\d+\.\d+|[a-z]+))?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Menu(LinkedHashMap<String, Entry>);

/// A section of the menu.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Entry {
    /// The section header.
    pub heading: String,

    /// The food items listed under the header.
    pub items: Vec<String>,

    /// Information indicating what ingredients are in the food, including whether it's vegetarian,
    /// vegan, etc.
    pub dietary_info: Option<String>,
}

impl Display for Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "*{}*\n", self.heading)?;

        let items = if self.items.is_empty() {
            vec![String::from("Nothing today")]
        } else {
            self.items.clone()
        };

        for item in &items {
            let dietary_info = if let Some(ref info) = self.dietary_info {
                format!(" (_{}_)", info)
            } else {
                String::default()
            };

            writeln!(f, "• {}{}", item, dietary_info)?;
        }

        Ok(())
    }
}

impl Menu {
    /// Returns the entries of the menu.
    pub fn entries(&self) -> Vec<Entry> {
        self.0.values().cloned().collect()
    }

    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> Result<String> {
        let mut output = String::default();

        for entry in self.entries() {
            write!(output, "{}", entry).unwrap();
        }

        if output.is_empty() {
            bail!(ErrorKind::EmptyMenu);
        }

        Ok(output)
    }
}

/// Retrieves and parses the menu for a given date.
pub fn retrieve_menu(date: &NaiveDate) -> Result<Menu> {
    let url = url_for_date(date);

    let mut res = reqwest::get(url.as_str()).map_err(|e| {
        ErrorKind::Network(e.to_string())
    })?;

    let body = if res.status().is_success() {
        let mut bytes = vec![];
        res.read_to_end(&mut bytes)?;
        String::from_utf8_lossy(&bytes).into_owned()
    } else {
        bail!(ErrorKind::Network(res.status().to_string()))
    };

    Ok(parse_menu(&body))
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!(
        "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.nsf\
        /weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
        monday.format("%m-%d-%Y"),
        days_from_monday + 1
    )).unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);
    let menu_node = document.find(Attr("id", "center_text")).next().unwrap();

    let mut menu = LinkedHashMap::new();
    let mut current_heading = None;

    for node in menu_node.children() {
        let text = node.text().trim().to_owned();

        if let Some("font-weight:bold;") = node.attr("style") {
            current_heading = Some(text.to_lowercase().to_title_case());
        } else {
            if let Some(ref heading) = current_heading {
                // Skip breakfast
                if heading == "Breakfast Special" {
                    continue;
                }

                // Skip nutrition and price information.
                if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
                    continue;
                }

                let entry = menu.entry(heading.clone()).or_insert_with(|| {
                    Entry {
                        heading: heading.to_owned(),
                        items: Vec::new(),
                        dietary_info: None,
                    }
                });

                if node.is(Name("div")) && !text.is_empty() {
                    entry.items.push(text);
                } else if let Some(caps) = INGREDIENTS_RE.captures(&text) {
                    entry.dietary_info = Some(caps[1].to_owned());
                }
            } else {
                println!("encountered entry without a heading");
                continue;
            }
        }
    }

    Menu(menu)
}

#[cfg(test)]
mod tests {
    use chrono::NaiveDate;
    use linked_hash_map::LinkedHashMap;

    use super::{Entry, Menu};

    #[test]
    fn parse_menu() {
        let html = r#"

CHEF'S SPECIAL PIZZA

        "#;

        let menu = super::parse_menu(html);
        let expected = {
            let mut menu = LinkedHashMap::new();
            menu.insert(
                String::from("Chef's Special Pizza"),
                Entry {
                    heading: String::from("Chef's Special Pizza"),
                    items: vec![],
                    dietary_info: None,
                },
            );
            Menu(menu)
        };

        assert_eq!(menu, expected);
    }

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(
            expected_url,
            &super::url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).to_string()
        );
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(
            expected_url,
            &super::url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).to_string()
        );

    }

    #[test]
    fn ingredients_regex() {
        use super::INGREDIENTS_RE;

        let test_cases = [
            ("Ingredients: Pork, Egg, Spicy", "Pork, Egg, Spicy"),
            (
                "Ingredients: Vegetarian - Contains Wheat, Dairy",
                "Vegetarian - Contains Wheat, Dairy",
            ),
            ("Ingredients: Vegan - Serving Size 12oz", "Vegan"),
        ];

        for &(text, ingredients) in &test_cases {
            let capture = INGREDIENTS_RE.captures(text).unwrap().get(1).unwrap();
            assert_eq!(capture.as_str(), ingredients);
        }
    }

    #[test]
    fn price_regex() {
        use super::PRICE_RE;

        let patterns = ["7.50", "0.25/oz", "2.15 / 2.65"];

        for pattern in &patterns {
            assert!(PRICE_RE.is_match(pattern), pattern.clone());
        }
    }
}
<|endoftext|>


<commit_before>use graph::Node;
use math::{compose, translate_transform, scale_transform};
use visible_graph::{GraphPt, VisibleGraph};

/// A map on which an RBattle game is played.
///
/// A `Map` holds everything that does not change over the course of an RBattle
/// game. This includes a graph, and a set of nodes that have goop sources.
#[derive(Debug)]
pub struct Map<G: VisibleGraph> {
    /// The graph of nodes comprising this map's territory.
    pub graph: G,

    /// The nodes of `graph` that contain goop sources.
    pub sources: Vec<Node>,

    /// Transformation from graph space to game space.
    pub graph_to_game: [[f32; 3]; 3],

    /// The aspect ratio (width / height) of the game rectangle.
    pub game_aspect: f32,

    /// The color of each player's goop, indexed by player number.
    pub player_colors: Vec<(u8, u8, u8)>,
}

impl<G: VisibleGraph> Map<G> {
    pub fn new(graph: G, sources: Vec<Node>, player_colors: Vec<(u8, u8, u8)>) -> Map<G> {
        // Compute the transformation from graph space, where points run from
        // (0, 0) to upper_right, to game space, where points run from (-1, -1)
        // to (1,1).
        let GraphPt(width, height) = graph.bounds();
        let game_aspect = width / height;
        let graph_to_game =
            compose(translate_transform(-1.0, -1.0),
                    scale_transform(2.0 / width, 2.0 / height));

        // A little margin inside the window is nice.
        let graph_to_game = compose(scale_transform(0.95, 0.95), graph_to_game);

        Map { graph, sources, graph_to_game, game_aspect, player_colors }
    }
}

/// A player id number.
#[derive(Debug, Copy, Clone)]
pub struct Player(pub usize);
<commit_msg>Derive Eq, PartialEq for Player.<commit_after>use graph::Node;
use math::{compose, translate_transform, scale_transform};
use visible_graph::{GraphPt, VisibleGraph};

/// A map on which an RBattle game is played.
///
/// A `Map` holds everything that does not change over the course of an RBattle
/// game. This includes a graph, and a set of nodes that have goop sources.
#[derive(Debug)]
pub struct Map<G: VisibleGraph> {
    /// The graph of nodes comprising this map's territory.
    pub graph: G,

    /// The nodes of `graph` that contain goop sources.
    pub sources: Vec<Node>,

    /// Transformation from graph space to game space.
    pub graph_to_game: [[f32; 3]; 3],

    /// The aspect ratio (width / height) of the game rectangle.
    pub game_aspect: f32,

    /// The color of each player's goop, indexed by player number.
    pub player_colors: Vec<(u8, u8, u8)>,
}

impl<G: VisibleGraph> Map<G> {
    pub fn new(graph: G, sources: Vec<Node>, player_colors: Vec<(u8, u8, u8)>) -> Map<G> {
        // Compute the transformation from graph space, where points run from
        // (0, 0) to upper_right, to game space, where points run from (-1, -1)
        // to (1,1).
        let GraphPt(width, height) = graph.bounds();
        let game_aspect = width / height;
        let graph_to_game =
            compose(translate_transform(-1.0, -1.0),
                    scale_transform(2.0 / width, 2.0 / height));

        // A little margin inside the window is nice.
        let graph_to_game = compose(scale_transform(0.95, 0.95), graph_to_game);

        Map { graph, sources, graph_to_game, game_aspect, player_colors }
    }
}

/// A player id number.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Player(pub usize);
<|endoftext|>


<commit_before>
pub mod loopback {
    use std::ops;
    use utility::parser;

    pub struct Packet<'a>(&'a [u8]);

    #[doc(hidden)]
    impl<'a> ops::Deref for Packet<'a> {
        type Target = &'a [u8];
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a> Packet<'a> {
        pub fn new(data: &'a [u8]) -> Self {
            Packet(data)
        }

        pub fn link(&self) -> Link {
            let link = &self[..4];
            match parser::le_u32(link) {
                2 => Link::IPv4,
                24 | 28 | 30 => Link::IPv6,

                7 => Link::OSI,
                23 => Link::IPX,

                otherwise => panic!("Unsupported link {}", otherwise),
            }
        }

        pub fn payload(&self) -> &[u8] {
            &self[4..]
        }
    }

    #[derive(Debug)]
    pub enum Link {
        IPv4,
        IPv6,
        OSI,
        IPX,
    }
}

pub mod ethernet {
    use std::ops;
    use std::fmt;
    use utility::parser;

    pub struct Frame<'a>(&'a [u8]);

    #[doc(hidden)]
    impl<'a> ops::Deref for Frame<'a> {
        type Target = &'a [u8];
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a> Frame<'a> {
        pub fn new(data: &'a [u8]) -> Self {
            Frame(data)
        }

        pub fn destination(&self) -> &[u8] {
            &self[..6]
        }

        pub fn source(&self) -> &[u8] {
            &self[6..12]
        }

        pub fn ethertype(&self) -> EtherType {
            parser::be_u16(&self[12..]).into()
        }

        pub fn payload(&self) -> &[u8] {
            &self[14..]
        }
    }

    impl<'a> fmt::Debug for Frame<'a> {
        fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.debug_struct("ethernet::Frame")
                .field("destination", &self.destination())
                .field("source", &self.source())
                .field("ethertype", &self.ethertype())
                .field("payload", &self.payload())
                .finish()
        }
    }

    #[derive(Debug, PartialEq, Clone)]
    pub enum EtherType {
        IPv4,
        ARP,
        IPv6,
        Unknown(u16),
    }

    impl From<u16> for EtherType {
        fn from(value: u16) -> Self {
            use self::EtherType::*;
            match value {
                0x0800 => IPv4,
                0x0806 => ARP,
                0x86DD => IPv6,
                otherwise => Unknown(otherwise),
            }
        }
    }
}
<commit_msg>Add support for VLAN frame parsing.<commit_after>
pub mod loopback {
    use std::ops;
    use utility::parser;

    pub struct Packet<'a>(&'a [u8]);

    #[doc(hidden)]
    impl<'a> ops::Deref for Packet<'a> {
        type Target = &'a [u8];
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a> Packet<'a> {
        pub fn new(data: &'a [u8]) -> Self {
            Packet(data)
        }

        pub fn link(&self) -> Link {
            let link = &self[..4];
            match parser::le_u32(link) {
                2 => Link::IPv4,
                24 | 28 | 30 => Link::IPv6,

                7 => Link::OSI,
                23 => Link::IPX,

                link => panic!("Unsupported link {}", link),
            }
        }

        pub fn payload(&self) -> &[u8] {
            &self[4..]
        }
    }

    #[derive(Debug)]
    pub enum Link {
        IPv4,
        IPv6,
        OSI,
        IPX,
    }
}

pub mod ethernet {
    use std::ops;
    use std::fmt;
    use utility::parser;

    pub struct Frame<'a>(&'a [u8]);

    #[doc(hidden)]
    impl<'a> ops::Deref for Frame<'a> {
        type Target = &'a [u8];
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a> Frame<'a> {
        pub fn new(data: &'a [u8]) -> Self {
            Frame(data)
        }

        pub fn destination(&self) -> &[u8] {
            &self[..6]
        }

        pub fn source(&self) -> &[u8] {
            &self[6..12]
        }

        pub fn ethertype(&self) -> EtherType {
            parser::be_u16(&self[12..]).into()
        }

        pub fn payload(&self) -> &[u8] {
            &self[14..]
        }
    }

    impl<'a> fmt::Debug for Frame<'a> {
        fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.debug_struct("ethernet::Frame")
                .field("destination", &self.destination())
                .field("source", &self.source())
                .field("ethertype", &self.ethertype())
                .field("payload", &self.payload())
                .finish()
        }
    }

    #[derive(Debug, PartialEq, Clone)]
    pub enum EtherType {
        IPv4,
        ARP,
        VLAN,
        IPv6,
        Unknown(u16),
    }

    impl From<u16> for EtherType {
        fn from(value: u16) -> Self {
            use self::EtherType::*;
            match value {
                0x0800 => IPv4,
                0x0806 => ARP,
                0x8100 => VLAN, // VLAN-tagged frame (IEEE 802.1Q)
                0x86DD => IPv6,
                e => Unknown(e),
            }
        }
    }

    pub mod vlan {
        use std::ops;
        use std::fmt;
        use utility::parser;

        pub struct Frame<'a>(&'a [u8]);

        #[doc(hidden)]
        impl<'a> ops::Deref for Frame<'a> {
            type Target = &'a [u8];
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl<'a> Frame<'a> {
            pub fn new(data: &'a [u8]) -> Self {
                Frame(data)
            }

            pub fn ethertype(&self) -> super::EtherType {
                parser::be_u16(&self[2..]).into()
            }

            pub fn payload(&self) -> &[u8] {
                &self[4..]
            }
        }

        impl<'a> fmt::Debug for Frame<'a> {
            fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
                fmtr.debug_struct("vlan::Frame")
                    .field("ethertype", &self.ethertype())
                    .finish()
            }
        }
    }
}
<|endoftext|>


<commit_before>// .env parsing
extern crate dotenv;
// command line argument parsing
extern crate clap;
// logging macros
#[macro_use]
extern crate log;
// console logging output
extern crate fern;
extern crate chrono;
// Screeps API
extern crate screeps_api;
// HTTP connection
extern crate hyper;
// secure HTTPS connection
extern crate hyper_rustls;
// json pretty printing
extern crate serde_json;

use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

use hyper::client::Client;
use hyper::net::HttpsConnector;

use screeps_api::sockets::{ParsedMessage, Channel, ChannelUpdate};
use screeps_api::sockets::ws::Result as WsResult;

/// Set up dotenv and retrieve a specific variable, informatively panicking if it does not exist.
fn env(var: &str) -> String {
    dotenv::dotenv().ok();
    match ::std::env::var(var) {
        Ok(value) => value,
        Err(e) => panic!("must have `{}` defined (err: {:?})", var, e),
    }
}

fn setup_logging(verbosity: u64) {
    let log_level = match verbosity {
        0 => log::LogLevelFilter::Warn,
        1 => log::LogLevelFilter::Info,
        _ => log::LogLevelFilter::Debug,
    };
    fern::Dispatch::new()
        .level(log_level)
        .level_for("rustls", log::LogLevelFilter::Warn)
        .level_for("hyper", log::LogLevelFilter::Warn)
        .format(|out, message, record| {
            let now = chrono::Local::now();

            out.finish(format_args!("[{}][{}] {}: {}",
                                    now.format("%H:%M:%S"),
                                    record.level(),
                                    record.target(),
                                    message));
        })
        .chain(std::io::stdout())
        .apply()
        // ignore errors
        .unwrap_or(());
}

#[derive(Clone, Debug)]
struct Config {
    cpu: bool,
    messages: bool,
    credits: bool,
    console: bool,
    map_view: Vec<String>,
}

impl Config {
    fn new(args: &clap::ArgMatches) -> Self {
        Config {
            cpu: args.is_present("cpu"),
            messages: args.is_present("messages"),
            credits: args.is_present("credits"),
            console: args.is_present("console"),
            map_view: args.values_of("map-view")
                .map(|it| it.map(|v| v.to_owned()).collect())
                .unwrap_or_else(|| Vec::new()),
        }
    }

    fn subscribe_with(&self, id: &str, sender: &mut screeps_api::sockets::Sender) -> WsResult<()> {
        sender.subscribe(Channel::ServerMessages)?;

        if self.cpu {
            sender.subscribe(Channel::user_cpu(id))?;
        }

        if self.messages {
            sender.subscribe(Channel::user_messages(id))?;
            sender.subscribe(Channel::user_conversation(id, "57fb16b6e4dd183b746435b0"))?;
        }

        if self.credits {
            sender.subscribe(Channel::user_credits(id))?;
        }

        if self.console {
            sender.subscribe(Channel::user_console(id))?;
        }

        for room_name in &self.map_view {
            sender.subscribe(Channel::room_map_view(&**room_name))?;
        }

        Ok(())
    }
}

struct Handler<T: screeps_api::TokenStorage> {
    sender: screeps_api::sockets::Sender,
    tokens: T,
    info: screeps_api::MyInfo,
    config: Config,
}

impl<T: screeps_api::TokenStorage> screeps_api::sockets::Handler for Handler<T> {
    fn on_message(&mut self, message: ParsedMessage) -> WsResult<()> {
        match message {
            ParsedMessage::AuthFailed => panic!("authentication with stored token failed!"),
            ParsedMessage::AuthOk { new_token } => {
                info!("authentication succeeded, now authenticated as {}.",
                      self.info.username);
                // return the token to the token storage in case we need it again - we won't in this example
                // program, but this is a good practice
                //
                // TODO: find an efficient way to do this automatically in the handler.
                self.tokens.return_token(new_token);

                self.config.subscribe_with(&self.info.user_id, &mut self.sender)?;

                info!("Subscribed.");
            }
            ParsedMessage::ChannelUpdate { update } => {
                match update {
                    ChannelUpdate::UserCpu { user_id, update } => info!("CPU: [{}] {:#?}", user_id, update),
                    ChannelUpdate::RoomMapView { room_name, update } => {
                        info!("Map View: [{}] {:?}", room_name, update);
                    }
                    ChannelUpdate::UserConsole { user_id, update } => {
                        info!("Console: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::UserCredits { user_id, update } => {
                        info!("Credits: [{}] {}", user_id, update);
                    }
                    ChannelUpdate::UserMessage { user_id, update } => {
                        info!("New message: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::UserConversation { user_id, target_user_id, update } => {
                        info!("Conversation update: [{}->{}] {:#?}",
                              user_id,
                              target_user_id,
                              update);
                    }
                    ChannelUpdate::Other { channel, update } => {
                        warn!("ChannelUpdate::Other: {}\n{}",
                              channel,
                              serde_json::to_string_pretty(&update).expect("failed to serialize json string"));
                    }
                }
            }
            ParsedMessage::ServerProtocol { protocol } => {
                info!("server protocol: {}", protocol);
            }
            ParsedMessage::ServerTime { time } => {
                info!("server time: {}", time);
            }
            ParsedMessage::ServerPackage { package } => {
                info!("server package: {}", package);
            }
            ParsedMessage::Other(other) => {
                warn!("ParsedMessage::Other: {}", other);
            }
        }

        Ok(())
    }

    /// Run on any websocket error or message parsing error.
    fn on_error(&mut self, err: screeps_api::sockets::Error) {
        error!("{}", err);
    }
}

fn main() {
    let cmd_arguments = clap::App::new("ws-debug")
        .arg(clap::Arg::with_name("verbose")
            .short("v")
            .long("verbose")
            .multiple(true)
            .help("Enables verbose logging"))
        .arg(clap::Arg::with_name("cpu")
            .short("p")
            .long("cpu")
            .help("Subscribe to user cpu and memory updates"))
        .arg(clap::Arg::with_name("credits")
            .short("c")
            .long("credits")
            .help("Subscribe to per-tick user credit updates"))
        .arg(clap::Arg::with_name("console")
            .short("o")
            .long("console")
            .help("Subscribe to user console messages"))
        .arg(clap::Arg::with_name("messages")
            .short("e")
            .long("messages")
            .help("Subscribe to user message alerts"))
        .arg(clap::Arg::with_name("map-view")
            .short("m")
            .long("map-view")
            .value_name("ROOM_NAME")
            .help("Subscribes to a map-view room")
            .takes_value(true)
            .multiple(true))
        .get_matches();
    setup_logging(cmd_arguments.occurrences_of("verbose"));

    let config = Config::new(&cmd_arguments);

    // Create a sharable hyper client
    let hyper = Arc::new(Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new())));
    // Create a sharable token storage.
    let token_storage = Arc::new(Mutex::new(VecDeque::new()));
    // Create the API client for this thread.
    let mut client = screeps_api::API::with_token(hyper, token_storage.clone());

    // Login using the API client - this will storage the auth token in token_storage.
    client.login(env("SCREEPS_API_USERNAME"), env("SCREEPS_API_PASSWORD")).expect("failed to login");

    let my_info = client.my_info().unwrap();

    info!("Logged in as {}, attempting to connect to stream.",
          my_info.username);

    let factory_token = token_storage.clone();
    let factory = move |sender| {
        Handler {
            sender: sender,
            tokens: factory_token.clone(),
            info: my_info.clone(),
            config: config.clone(),
        }
    };

    // TODO: somehow create a way to go from API url to websocket url.
    screeps_api::sockets::connect("wss://screeps.com/socket/785/40128567/websocket",
                                  factory,
                                  token_storage)
        .expect("failed to connect to socket");
}
<commit_msg>Slight usability improvement for ws-debug.<commit_after>// .env parsing
extern crate dotenv;
// command line argument parsing
extern crate clap;
// logging macros
#[macro_use]
extern crate log;
// console logging output
extern crate fern;
extern crate chrono;
// Screeps API
extern crate screeps_api;
// HTTP connection
extern crate hyper;
// secure HTTPS connection
extern crate hyper_rustls;
// json pretty printing
extern crate serde_json;

use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

use hyper::client::Client;
use hyper::net::HttpsConnector;

use screeps_api::sockets::{ParsedMessage, Channel, ChannelUpdate};
use screeps_api::sockets::ws::Result as WsResult;

/// Set up dotenv and retrieve a specific variable, informatively panicking if it does not exist.
fn env(var: &str) -> String {
    dotenv::dotenv().ok();
    match ::std::env::var(var) {
        Ok(value) => value,
        Err(e) => panic!("must have `{}` defined (err: {:?})", var, e),
    }
}

fn setup_logging(verbosity: u64) {
    let log_level = match verbosity {
        0 => log::LogLevelFilter::Warn,
        1 => log::LogLevelFilter::Info,
        _ => log::LogLevelFilter::Debug,
    };
    fern::Dispatch::new()
        .level(log_level)
        .level_for("rustls", log::LogLevelFilter::Warn)
        .level_for("hyper", log::LogLevelFilter::Warn)
        .format(|out, message, record| {
            let now = chrono::Local::now();

            out.finish(format_args!("[{}][{}] {}: {}",
                                    now.format("%H:%M:%S"),
                                    record.level(),
                                    record.target(),
                                    message));
        })
        .chain(std::io::stdout())
        .apply()
        // ignore errors
        .unwrap_or(());
}

#[derive(Clone, Debug)]
struct Config {
    cpu: bool,
    messages: bool,
    credits: bool,
    console: bool,
    map_view: Vec<String>,
}

impl Config {
    fn new(args: &clap::ArgMatches) -> Self {
        Config {
            cpu: args.is_present("cpu"),
            messages: args.is_present("messages"),
            credits: args.is_present("credits"),
            console: args.is_present("console"),
            map_view: args.values_of("map-view")
                .map(|it| it.map(|v| v.to_uppercase()).collect())
                .unwrap_or_else(|| Vec::new()),
        }
    }

    fn subscribe_with(&self, id: &str, sender: &mut screeps_api::sockets::Sender) -> WsResult<()> {
        sender.subscribe(Channel::ServerMessages)?;

        if self.cpu {
            sender.subscribe(Channel::user_cpu(id))?;
        }

        if self.messages {
            sender.subscribe(Channel::user_messages(id))?;
            sender.subscribe(Channel::user_conversation(id, "57fb16b6e4dd183b746435b0"))?;
        }

        if self.credits {
            sender.subscribe(Channel::user_credits(id))?;
        }

        if self.console {
            sender.subscribe(Channel::user_console(id))?;
        }

        for room_name in &self.map_view {
            sender.subscribe(Channel::room_map_view(&**room_name))?;
        }

        Ok(())
    }
}

struct Handler<T: screeps_api::TokenStorage> {
    sender: screeps_api::sockets::Sender,
    tokens: T,
    info: screeps_api::MyInfo,
    config: Config,
}

impl<T: screeps_api::TokenStorage> screeps_api::sockets::Handler for Handler<T> {
    fn on_message(&mut self, message: ParsedMessage) -> WsResult<()> {
        match message {
            ParsedMessage::AuthFailed => panic!("authentication with stored token failed!"),
            ParsedMessage::AuthOk { new_token } => {
                info!("authentication succeeded, now authenticated as {}.",
                      self.info.username);
                // return the token to the token storage in case we need it again - we won't in this example
                // program, but this is a good practice
                //
                // TODO: find an efficient way to do this automatically in the handler.
                self.tokens.return_token(new_token);

                self.config.subscribe_with(&self.info.user_id, &mut self.sender)?;

                warn!("Subscribed.");
            }
            ParsedMessage::ChannelUpdate { update } => {
                match update {
                    ChannelUpdate::UserCpu { user_id, update } => info!("CPU: [{}] {:#?}", user_id, update),
                    ChannelUpdate::RoomMapView { room_name, update } => {
                        info!("Map View: [{}] {:?}", room_name, update);
                    }
                    ChannelUpdate::UserConsole { user_id, update } => {
                        info!("Console: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::UserCredits { user_id, update } => {
                        info!("Credits: [{}] {}", user_id, update);
                    }
                    ChannelUpdate::UserMessage { user_id, update } => {
                        info!("New message: [{}] {:#?}", user_id, update);
                    }
                    ChannelUpdate::UserConversation { user_id, target_user_id, update } => {
                        info!("Conversation update: [{}->{}] {:#?}",
                              user_id,
                              target_user_id,
                              update);
                    }
                    ChannelUpdate::Other { channel, update } => {
                        warn!("ChannelUpdate::Other: {}\n{}",
                              channel,
                              serde_json::to_string_pretty(&update).expect("failed to serialize json string"));
                    }
                }
            }
            ParsedMessage::ServerProtocol { protocol } => {
                info!("server protocol: {}", protocol);
            }
            ParsedMessage::ServerTime { time } => {
                info!("server time: {}", time);
            }
            ParsedMessage::ServerPackage { package } => {
                info!("server package: {}", package);
            }
            ParsedMessage::Other(other) => {
                warn!("ParsedMessage::Other: {}", other);
            }
        }

        Ok(())
    }

    /// Run on any websocket error or message parsing error.
    fn on_error(&mut self, err: screeps_api::sockets::Error) {
        error!("{}", err);
    }
}

fn main() {
    let cmd_arguments = clap::App::new("ws-debug")
        .arg(clap::Arg::with_name("verbose")
            .short("v")
            .long("verbose")
            .multiple(true)
            .help("Enables verbose logging"))
        .arg(clap::Arg::with_name("cpu")
            .short("p")
            .long("cpu")
            .help("Subscribe to user cpu and memory updates"))
        .arg(clap::Arg::with_name("credits")
            .short("c")
            .long("credits")
            .help("Subscribe to per-tick user credit updates"))
        .arg(clap::Arg::with_name("console")
            .short("o")
            .long("console")
            .help("Subscribe to user console messages"))
        .arg(clap::Arg::with_name("messages")
            .short("e")
            .long("messages")
            .help("Subscribe to user message alerts"))
        .arg(clap::Arg::with_name("map-view")
            .short("m")
            .long("map-view")
            .value_name("ROOM_NAME")
            .help("Subscribes to a map-view room")
            .takes_value(true)
            .multiple(true))
        .get_matches();
    setup_logging(cmd_arguments.occurrences_of("verbose"));

    let config = Config::new(&cmd_arguments);

    // Create a sharable hyper client
    let hyper = Arc::new(Client::with_connector(HttpsConnector::new(hyper_rustls::TlsClient::new())));
    // Create a sharable token storage.
    let token_storage = Arc::new(Mutex::new(VecDeque::new()));
    // Create the API client for this thread.
    let mut client = screeps_api::API::with_token(hyper, token_storage.clone());

    // Login using the API client - this will storage the auth token in token_storage.
    client.login(env("SCREEPS_API_USERNAME"), env("SCREEPS_API_PASSWORD")).expect("failed to login");

    let my_info = client.my_info().unwrap();

    info!("Logged in as {}, attempting to connect to stream.",
          my_info.username);

    let factory_token = token_storage.clone();
    let factory = move |sender| {
        Handler {
            sender: sender,
            tokens: factory_token.clone(),
            info: my_info.clone(),
            config: config.clone(),
        }
    };

    // TODO: somehow create a way to go from API url to websocket url.
    screeps_api::sockets::connect("wss://screeps.com/socket/785/40128567/websocket",
                                  factory,
                                  token_storage)
        .expect("failed to connect to socket");
}
<|endoftext|>


<commit_before>use super::*;
use super::internal::*;
use std::str::Chars;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

impl<'a> ParallelString for &'a str {
    type Chars = ParChars<'a>;

    fn par_chars(self) -> Self::Chars {
        ParChars {
            chars: self
        }
    }
}

pub struct ParChars<'a> {
    chars: &'a str
}

impl<'a> ParallelIterator for ParChars<'a> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(self, consumer)
    }
}

impl<'a> UnindexedProducer for ParChars<'a> {
    fn can_split(&self) -> bool {
        // This is pessimistic, as we only *know* there are multiple characters
        // when it's longer than Unicode's maximum UTF-8 length of 4.  There
        // could be smaller characters, but it's ok not to split maximally.
        self.chars.len() > 4
    }

    fn split(self) -> (Self, Self) {
        let mid = self.chars.len() / 2;

        // We want to split near the midpoint, but we need to find an actual
        // character boundary.  So we look at the raw bytes, first scanning
        // forward from the midpoint for a boundary, then trying backward.
        let (left, right) = self.chars.as_bytes().split_at(mid);
        let index = right.iter().cloned().position(is_char_boundary).map(|i| mid + i)
            .or_else(|| left.iter().cloned().rposition(is_char_boundary))
            .unwrap_or(0);

        let (left, right) = self.chars.split_at(index);
        (ParChars { chars: left }, ParChars { chars: right })
    }
}

impl<'a> IntoIterator for ParChars<'a>
{
    type Item = char;
    type IntoIter = Chars<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.chars.chars()
    }
}
<commit_msg>Run rustfmt on par_iter::string<commit_after>use super::*;
use super::internal::*;
use std::str::Chars;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

impl<'a> ParallelString for &'a str {
    type Chars = ParChars<'a>;

    fn par_chars(self) -> Self::Chars {
        ParChars { chars: self }
    }
}

pub struct ParChars<'a> {
    chars: &'a str,
}

impl<'a> ParallelIterator for ParChars<'a> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(self, consumer)
    }
}

impl<'a> UnindexedProducer for ParChars<'a> {
    fn can_split(&self) -> bool {
        // This is pessimistic, as we only *know* there are multiple characters
        // when it's longer than Unicode's maximum UTF-8 length of 4.  There
        // could be smaller characters, but it's ok not to split maximally.
        self.chars.len() > 4
    }

    fn split(self) -> (Self, Self) {
        let mid = self.chars.len() / 2;

        // We want to split near the midpoint, but we need to find an actual
        // character boundary.  So we look at the raw bytes, first scanning
        // forward from the midpoint for a boundary, then trying backward.
        let (left, right) = self.chars.as_bytes().split_at(mid);
        let index = right.iter()
            .cloned()
            .position(is_char_boundary)
            .map(|i| mid + i)
            .or_else(|| left.iter().cloned().rposition(is_char_boundary))
            .unwrap_or(0);

        let (left, right) = self.chars.split_at(index);
        (ParChars { chars: left }, ParChars { chars: right })
    }
}

impl<'a> IntoIterator for ParChars<'a> {
    type Item = char;
    type IntoIter = Chars<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.chars.chars()
    }
}
<|endoftext|>


<commit_before>use crate::bitset::BitSet;
use crate::ir;
use crate::isa::TargetIsa;
use std::vec::Vec;

/// Wrapper class for longer bit vectors that cannot be represented by a single BitSet.
#[derive(Clone, Debug)]
pub struct Stackmap {
    bitmap: Vec<BitSet<u32>>,
}

impl Stackmap {
    /// Create a stackmap based on where references are located on a function's stack.
    pub fn from_values(
        args: &[ir::entities::Value],
        func: &ir::Function,
        isa: &dyn TargetIsa,
    ) -> Self {
        let loc = &func.locations;
        let mut live_ref_in_stack_slot = std::collections::HashSet::new();
        // References can be in registers, and live registers values are pushed onto the stack before calls and traps.
        // TODO: Implement register maps. If a register containing a reference is spilled and reused after a safepoint,
        // it could contain a stale reference value if the garbage collector relocated the value.
        for val in args {
            if let Some(value_loc) = loc.get(*val) {
                match *value_loc {
                    ir::ValueLoc::Stack(stack_slot) => live_ref_in_stack_slot.insert(stack_slot),
                    _ => false,
                };
            }
        }

        // SpiderMonkey stackmap structure:
        // <trap reg dump> + <general spill> + <frame> + <inbound args>
        // Bit vector goes from lower addresses to higher addresses.

        // TODO: Get trap register layout from Spidermonkey and prepend to bitvector below.
        let stack = &func.stack_slots;
        let frame_size = stack.frame_size.unwrap();
        let word_size = ir::stackslot::StackSize::from(isa.pointer_bytes());
        let num_words = (frame_size / word_size) as usize;
        let mut vec = std::vec::Vec::with_capacity(num_words);

        vec.resize(num_words, false);

        // Frame (includes spills and inbound args).
        for (ss, ssd) in stack.iter() {
            if live_ref_in_stack_slot.contains(&ss) {
                // Assumption: greater magnitude of offset imply higher address.
                let index = (((ssd.offset.unwrap().abs() as u32) - ssd.size) / word_size) as usize;
                vec[index] = true;
            }
        }

        Stackmap::from_vec(&vec)
    }

    /// Create a vec of Bitsets from a vec of bools.
    pub fn from_vec(vec: &Vec<bool>) -> Self {
        let mut rem = vec.len();
        let num_word = ((rem as f32) / 32.0).ceil() as usize;
        let mut bitmap = Vec::with_capacity(num_word);

        for i in 0..num_word {
            let mut curr_word = 0;
            let count = if rem > 32 { 32 } else { rem };
            for j in 0..count {
                if vec[i * 32 + j] {
                    curr_word |= 1 << j;
                }
            }
            bitmap.push(BitSet::<u32>(curr_word));
            rem -= count;
        }
        Self { bitmap }
    }

    /// Returns a specified bit.
    pub fn get_bit(&self, bit_index: usize) -> bool {
        assert!(bit_index < 32 * self.bitmap.len());
        let word_index = bit_index / 32;
        let word_offset = (bit_index % 32) as u8;
        self.bitmap[word_index].contains(word_offset)
    }
}

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

    #[test]
    fn stackmaps() {
        let vec: Vec<bool> = Vec::new();
        assert!(Stackmap::from_vec(&vec).bitmap.is_empty());

        let mut vec: [bool; 32] = Default::default();
        let set_true_idx = [5, 7, 24, 31];

        for idx in set_true_idx.iter() {
            vec[*idx] = true;
        }

        let mut vec = vec.to_vec();
        assert_eq!(
            vec![BitSet::<u32>(2164261024)],
            Stackmap::from_vec(&vec).bitmap
        );

        vec.push(false);
        vec.push(true);
        let res = Stackmap::from_vec(&vec);
        assert_eq!(
            vec![BitSet::<u32>(2164261024), BitSet::<u32>(2)],
            res.bitmap
        );

        assert!(res.get_bit(5));
        assert!(res.get_bit(31));
        assert!(res.get_bit(33));
        assert!(!res.get_bit(1));
    }
}
<commit_msg>Simplify and rename `Stackmap::from_vec` (#1032)<commit_after>use crate::bitset::BitSet;
use crate::ir;
use crate::isa::TargetIsa;
use std::vec::Vec;

type Num = u32;
const NUM_BITS: usize = std::mem::size_of::<Num>() * 8;

/// Wrapper class for longer bit vectors that cannot be represented by a single BitSet.
#[derive(Clone, Debug)]
pub struct Stackmap {
    bitmap: Vec<BitSet<Num>>,
}

impl Stackmap {
    /// Create a stackmap based on where references are located on a function's stack.
    pub fn from_values(
        args: &[ir::entities::Value],
        func: &ir::Function,
        isa: &dyn TargetIsa,
    ) -> Self {
        let loc = &func.locations;
        let mut live_ref_in_stack_slot = std::collections::HashSet::new();
        // References can be in registers, and live registers values are pushed onto the stack before calls and traps.
        // TODO: Implement register maps. If a register containing a reference is spilled and reused after a safepoint,
        // it could contain a stale reference value if the garbage collector relocated the value.
        for val in args {
            if let Some(value_loc) = loc.get(*val) {
                match *value_loc {
                    ir::ValueLoc::Stack(stack_slot) => live_ref_in_stack_slot.insert(stack_slot),
                    _ => false,
                };
            }
        }

        // SpiderMonkey stackmap structure:
        // <trap reg dump> + <general spill> + <frame> + <inbound args>
        // Bit vector goes from lower addresses to higher addresses.

        // TODO: Get trap register layout from Spidermonkey and prepend to bitvector below.
        let stack = &func.stack_slots;
        let frame_size = stack.frame_size.unwrap();
        let word_size = ir::stackslot::StackSize::from(isa.pointer_bytes());
        let num_words = (frame_size / word_size) as usize;
        let mut vec = std::vec::Vec::with_capacity(num_words);

        vec.resize(num_words, false);

        // Frame (includes spills and inbound args).
        for (ss, ssd) in stack.iter() {
            if live_ref_in_stack_slot.contains(&ss) {
                // Assumption: greater magnitude of offset imply higher address.
                let index = (((ssd.offset.unwrap().abs() as u32) - ssd.size) / word_size) as usize;
                vec[index] = true;
            }
        }

        Stackmap::from_slice(&vec)
    }

    /// Create a vec of Bitsets from a slice of bools.
    pub fn from_slice(vec: &[bool]) -> Self {
        let len = vec.len();
        let num_word = len / NUM_BITS + (len % NUM_BITS != 0) as usize;
        let mut bitmap = Vec::with_capacity(num_word);

        for segment in vec.chunks(NUM_BITS) {
            let mut curr_word = 0;
            for (i, set) in segment.iter().enumerate() {
                if *set {
                    curr_word |= 1 << i;
                }
            }
            bitmap.push(BitSet(curr_word));
        }
        Self { bitmap }
    }

    /// Returns a specified bit.
    pub fn get_bit(&self, bit_index: usize) -> bool {
        assert!(bit_index < NUM_BITS * self.bitmap.len());
        let word_index = bit_index / NUM_BITS;
        let word_offset = (bit_index % NUM_BITS) as u8;
        self.bitmap[word_index].contains(word_offset)
    }
}

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

    #[test]
    fn stackmaps() {
        let vec: Vec<bool> = Vec::new();
        assert!(Stackmap::from_slice(&vec).bitmap.is_empty());

        let mut vec: [bool; NUM_BITS] = Default::default();
        let set_true_idx = [5, 7, 24, 31];

        for &idx in &set_true_idx {
            vec[idx] = true;
        }

        let mut vec = vec.to_vec();
        assert_eq!(
            vec![BitSet::<Num>(2164261024)],
            Stackmap::from_slice(&vec).bitmap
        );

        vec.push(false);
        vec.push(true);
        let res = Stackmap::from_slice(&vec);
        assert_eq!(
            vec![BitSet::<Num>(2164261024), BitSet::<Num>(2)],
            res.bitmap
        );

        assert!(res.get_bit(5));
        assert!(res.get_bit(31));
        assert!(res.get_bit(33));
        assert!(!res.get_bit(1));
    }
}
<|endoftext|>


<commit_before>use pagecache::{Measure, M};

use super::*;

/// An iterator over keys in a `Tree`
pub struct Keys<'a>(Iter<'a>);

impl<'a> Iterator for Keys<'a> {
    type Item = Result<Vec<u8>, ()>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|r| r.map(|(k, _v)| k))
    }
}

impl<'a> DoubleEndedIterator for Keys<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|r| r.map(|(k, _v)| k))
    }
}

/// An iterator over values in a `Tree`
pub struct Values<'a>(Iter<'a>);

impl<'a> Iterator for Values<'a> {
    type Item = Result<PinnedValue, ()>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|r| r.map(|(_k, v)| v))
    }
}

impl<'a> DoubleEndedIterator for Values<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|r| r.map(|(_k, v)| v))
    }
}

/// An iterator over keys and values in a `Tree`.
pub struct Iter<'a> {
    pub(super) id: PageId,
    pub(super) inner: &'a Tree,
    pub(super) last_key: Key,
    pub(super) inclusive: bool,
    pub(super) broken: Option<Error<()>>,
    pub(super) done: bool,
    pub(super) guard: Guard,
    // TODO we have to refactor this in light of pages being deleted
}

impl<'a> Iter<'a> {
    /// Iterate over the keys of this Tree
    pub fn keys(self) -> Keys<'a> {
        Keys(self)
    }

    /// Iterate over the values of this Tree
    pub fn values(self) -> Values<'a> {
        Values(self)
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Result<(Vec<u8>, PinnedValue), ()>;

    fn next(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        if self.done {
            return None;
        } else if let Some(broken) = self.broken.take() {
            self.done = true;
            return Some(Err(broken));
        };

        loop {
            let pin_guard = self.guard.clone();
            let get_guard = self.guard.clone();

            let res = self
                .inner
                .pages
                .get(self.id, &get_guard)
                .map(|page_get| page_get.unwrap());

            if let Err(e) = res {
                error!("iteration failed: {:?}", e);
                self.done = true;
                return Some(Err(e.danger_cast()));
            }

            // TODO (when implementing merge support) this could
            // be None if the node was removed since the last
            // iteration, and we need to just get the inner
            // node again...
            let (frag, _ptr) = res.unwrap();
            let node = frag.unwrap_base();
            let leaf =
                node.data.leaf_ref().expect("node should be a leaf");
            let prefix = node.lo.inner();

            let search = if self.inclusive {
                self.inclusive = false;
                leaf.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
                .ok()
                .or_else(|| {
                    binary_search_gt(leaf, |&(ref k, ref _v)| {
                        prefix_cmp_encoded(k, &self.last_key, prefix)
                    })
                })
            } else {
                binary_search_gt(leaf, |&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
            };

            if let Some(idx) = search {
                let (k, v) = &leaf[idx];
                let decoded_k = prefix_decode(prefix, &k);
                self.last_key = decoded_k.to_vec();
                let ret =
                    Ok((decoded_k, PinnedValue::new(&*v, pin_guard)));
                return Some(ret);
            }

            match node.next {
                Some(id) => self.id = id,
                None => {
                    assert_eq!(
                        node.hi,
                        Bound::Inf,
                        "if a node has no right sibling, \
                         it must be the upper-bound node"
                    );
                    return None;
                }
            }
        }
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        if self.done {
            return None;
        } else if let Some(broken) = self.broken.take() {
            self.done = true;
            return Some(Err(broken));
        };

        loop {
            let pin_guard = self.guard.clone();
            let get_guard = self.guard.clone();

            let res = self
                .inner
                .pages
                .get(self.id, &get_guard)
                .map(|page_get| page_get.unwrap());

            if let Err(e) = res {
                error!("iteration failed: {:?}", e);
                self.done = true;
                return Some(Err(e.danger_cast()));
            }

            // TODO (when implementing merge support) this could
            // be None if the node was removed since the last
            // iteration, and we need to just get the inner
            // node again...
            let (frag, _ptr) = res.unwrap();
            let node = frag.unwrap_base();
            let leaf =
                node.data.leaf_ref().expect("node should be a leaf");
            let prefix = node.lo.inner();

            let search = if self.inclusive {
                self.inclusive = false;
                leaf.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
                .ok()
                .or_else(|| {
                    binary_search_lt(leaf, |&(ref k, ref _v)| {
                        prefix_cmp_encoded(k, &self.last_key, prefix)
                    })
                })
            } else {
                binary_search_lt(leaf, |&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
            };

            if let Some(idx) = search {
                let (k, v) = &leaf[idx];
                let decoded_k = prefix_decode(prefix, &k);
                self.last_key = decoded_k.to_vec();
                let ret =
                    Ok((decoded_k, PinnedValue::new(&*v, pin_guard)));
                return Some(ret);
            }

            // we need to get the node to the right of ours by
            // guessing a key that might land on it, and then
            // fast-forwarding through the right child pointers
            // if we went too far to the left.
            let pred = possible_predecessor(prefix)?;
            let mut next_node =
                match self.inner.path_for_key(pred, &get_guard) {
                    Err(e) => {
                        error!("next_back iteration failed: {:?}", e);
                        self.done = true;
                        return Some(Err(e.danger_cast()));
                    }
                    Ok(path) => path.last().unwrap().0.unwrap_base(),
                };
            while next_node.next != Some(node.id)
                && next_node.lo < node.lo
            {
                let res = self
                    .inner
                    .pages
                    .get(next_node.next?, &get_guard)
                    .map(|page_get| page_get.unwrap());

                if let Err(e) = res {
                    error!("iteration failed: {:?}", e);
                    self.done = true;
                    return Some(Err(e.danger_cast()));
                }
                let (frag, _ptr) = res.unwrap();
                next_node = frag.unwrap_base();
            }

            self.id = next_node.id;
        }
    }
}

fn possible_predecessor(s: &[u8]) -> Option<Vec<u8>> {
    let mut ret = s.to_vec();
    match ret.pop() {
        None => None,
        Some(i) if i == 0 => Some(ret),
        Some(i) => {
            ret.push(i - 1);
            for _ in 0..4 {
                ret.push(255);
            }
            Some(ret)
        }
    }
}

#[test]
fn test_possible_predecessor() {
    assert_eq!(possible_predecessor(b""), None);
    assert_eq!(possible_predecessor(&[0]), Some(vec![]));
    assert_eq!(possible_predecessor(&[0, 0]), Some(vec![0]));
    assert_eq!(
        possible_predecessor(&[0, 1]),
        Some(vec![0, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[0, 2]),
        Some(vec![0, 1, 255, 255, 255, 255])
    );
    assert_eq!(possible_predecessor(&[1, 0]), Some(vec![1]));
    assert_eq!(
        possible_predecessor(&[1, 1]),
        Some(vec![1, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[155]),
        Some(vec![154, 255, 255, 255, 255])
    );
}
<commit_msg>Small cleanup of reverse iterator<commit_after>use pagecache::{Measure, M};

use super::*;

/// An iterator over keys in a `Tree`
pub struct Keys<'a>(Iter<'a>);

impl<'a> Iterator for Keys<'a> {
    type Item = Result<Vec<u8>, ()>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|r| r.map(|(k, _v)| k))
    }
}

impl<'a> DoubleEndedIterator for Keys<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|r| r.map(|(k, _v)| k))
    }
}

/// An iterator over values in a `Tree`
pub struct Values<'a>(Iter<'a>);

impl<'a> Iterator for Values<'a> {
    type Item = Result<PinnedValue, ()>;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|r| r.map(|(_k, v)| v))
    }
}

impl<'a> DoubleEndedIterator for Values<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.0.next_back().map(|r| r.map(|(_k, v)| v))
    }
}

/// An iterator over keys and values in a `Tree`.
pub struct Iter<'a> {
    pub(super) id: PageId,
    pub(super) inner: &'a Tree,
    pub(super) last_key: Key,
    pub(super) inclusive: bool,
    pub(super) broken: Option<Error<()>>,
    pub(super) done: bool,
    pub(super) guard: Guard,
    // TODO we have to refactor this in light of pages being deleted
}

impl<'a> Iter<'a> {
    /// Iterate over the keys of this Tree
    pub fn keys(self) -> Keys<'a> {
        Keys(self)
    }

    /// Iterate over the values of this Tree
    pub fn values(self) -> Values<'a> {
        Values(self)
    }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Result<(Vec<u8>, PinnedValue), ()>;

    fn next(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        if self.done {
            return None;
        } else if let Some(broken) = self.broken.take() {
            self.done = true;
            return Some(Err(broken));
        };

        loop {
            let pin_guard = self.guard.clone();
            let get_guard = self.guard.clone();

            let res = self
                .inner
                .pages
                .get(self.id, &get_guard)
                .map(|page_get| page_get.unwrap());

            if let Err(e) = res {
                error!("iteration failed: {:?}", e);
                self.done = true;
                return Some(Err(e.danger_cast()));
            }

            // TODO (when implementing merge support) this could
            // be None if the node was removed since the last
            // iteration, and we need to just get the inner
            // node again...
            let (frag, _ptr) = res.unwrap();
            let node = frag.unwrap_base();
            let leaf =
                node.data.leaf_ref().expect("node should be a leaf");
            let prefix = node.lo.inner();

            let search = if self.inclusive {
                self.inclusive = false;
                leaf.binary_search_by(|&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
                .ok()
                .or_else(|| {
                    binary_search_gt(leaf, |&(ref k, ref _v)| {
                        prefix_cmp_encoded(k, &self.last_key, prefix)
                    })
                })
            } else {
                binary_search_gt(leaf, |&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
            };

            if let Some(idx) = search {
                let (k, v) = &leaf[idx];
                let decoded_k = prefix_decode(prefix, &k);
                self.last_key = decoded_k.to_vec();
                let ret =
                    Ok((decoded_k, PinnedValue::new(&*v, pin_guard)));
                return Some(ret);
            }

            match node.next {
                Some(id) => self.id = id,
                None => {
                    assert_eq!(
                        node.hi,
                        Bound::Inf,
                        "if a node has no right sibling, \
                         it must be the upper-bound node"
                    );
                    return None;
                }
            }
        }
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let _measure = Measure::new(&M.tree_scan);

        if self.done {
            return None;
        } else if let Some(broken) = self.broken.take() {
            self.done = true;
            return Some(Err(broken));
        };

        loop {
            let pin_guard = self.guard.clone();
            let get_guard = self.guard.clone();

            let res = self
                .inner
                .pages
                .get(self.id, &get_guard)
                .map(|page_get| page_get.unwrap());

            if let Err(e) = res {
                error!("iteration failed: {:?}", e);
                self.done = true;
                return Some(Err(e.danger_cast()));
            }

            // TODO (when implementing merge support) this could
            // be None if the node was removed since the last
            // iteration, and we need to just get the inner
            // node again...
            let (frag, _ptr) = res.unwrap();
            let node = frag.unwrap_base();
            let leaf =
                node.data.leaf_ref().expect("node should be a leaf");
            let prefix = node.lo.inner();

            let search = if self.inclusive {
                self.inclusive = false;
                binary_search_lub(leaf, |&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
            } else {
                binary_search_lt(leaf, |&(ref k, ref _v)| {
                    prefix_cmp_encoded(k, &self.last_key, prefix)
                })
            };

            if let Some(idx) = search {
                let (k, v) = &leaf[idx];
                let decoded_k = prefix_decode(prefix, &k);
                self.last_key = decoded_k.to_vec();
                let ret =
                    Ok((decoded_k, PinnedValue::new(&*v, pin_guard)));
                return Some(ret);
            }

            // we need to get the node to the left of ours by
            // guessing a key that might land on it, and then
            // fast-forwarding through the right child pointers
            // if we went too far to the left.
            let pred = possible_predecessor(prefix)?;
            let mut next_node =
                match self.inner.path_for_key(pred, &get_guard) {
                    Err(e) => {
                        error!("next_back iteration failed: {:?}", e);
                        self.done = true;
                        return Some(Err(e.danger_cast()));
                    }
                    Ok(path) => path.last().unwrap().0.unwrap_base(),
                };
            while next_node.next != Some(node.id)
                && next_node.lo < node.lo
            {
                let res = self
                    .inner
                    .pages
                    .get(next_node.next?, &get_guard)
                    .map(|page_get| page_get.unwrap());

                if let Err(e) = res {
                    error!("iteration failed: {:?}", e);
                    self.done = true;
                    return Some(Err(e.danger_cast()));
                }
                let (frag, _ptr) = res.unwrap();
                next_node = frag.unwrap_base();
            }

            self.id = next_node.id;
        }
    }
}

fn possible_predecessor(s: &[u8]) -> Option<Vec<u8>> {
    let mut ret = s.to_vec();
    match ret.pop() {
        None => None,
        Some(i) if i == 0 => Some(ret),
        Some(i) => {
            ret.push(i - 1);
            for _ in 0..4 {
                ret.push(255);
            }
            Some(ret)
        }
    }
}

#[test]
fn test_possible_predecessor() {
    assert_eq!(possible_predecessor(b""), None);
    assert_eq!(possible_predecessor(&[0]), Some(vec![]));
    assert_eq!(possible_predecessor(&[0, 0]), Some(vec![0]));
    assert_eq!(
        possible_predecessor(&[0, 1]),
        Some(vec![0, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[0, 2]),
        Some(vec![0, 1, 255, 255, 255, 255])
    );
    assert_eq!(possible_predecessor(&[1, 0]), Some(vec![1]));
    assert_eq!(
        possible_predecessor(&[1, 1]),
        Some(vec![1, 0, 255, 255, 255, 255])
    );
    assert_eq!(
        possible_predecessor(&[155]),
        Some(vec![154, 255, 255, 255, 255])
    );
}
<|endoftext|>


<commit_before>//! Types for the `m.reaction` event.

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};

use super::relation::Annotation;

/// The payload for a `m.reaction` event.
///
/// A reaction to another event.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.reaction", kind = MessageLike)]
pub struct ReactionEventContent {
    /// Information about the related event.
    #[serde(rename = "m.relates_to")]
    pub relates_to: Annotation,
}

impl ReactionEventContent {
    /// Creates a new `ReactionEventContent` from the given annotation.
    ///
    /// You can also construct a `ReactionEventContent` from an annotation using `From` / `Into`.
    pub fn new(relates_to: Annotation) -> Self {
        Self { relates_to }
    }
}

impl From<Annotation> for ReactionEventContent {
    fn from(relates_to: Annotation) -> Self {
        Self::new(relates_to)
    }
}

#[cfg(test)]
mod tests {
    use assert_matches::assert_matches;
    use serde_json::{from_value as from_json_value, json};

    use super::ReactionEventContent;

    #[test]
    fn deserialize() {
        let json = json!({
            "m.relates_to": {
                "rel_type": "m.annotation",
                "event_id": "$1598361704261elfgc:localhost",
                "key": "🦛",
            }
        });

        let relates_to = assert_matches!(
            from_json_value::<ReactionEventContent>(json),
            Ok(ReactionEventContent { relates_to }) => relates_to
        );
        assert_eq!(relates_to.event_id, "$1598361704261elfgc:localhost");
        assert_eq!(relates_to.key, "🦛");
    }
}
<commit_msg>events: Add serialization test for reaction<commit_after>//! Types for the `m.reaction` event.

use ruma_macros::EventContent;
use serde::{Deserialize, Serialize};

use super::relation::Annotation;

/// The payload for a `m.reaction` event.
///
/// A reaction to another event.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.reaction", kind = MessageLike)]
pub struct ReactionEventContent {
    /// Information about the related event.
    #[serde(rename = "m.relates_to")]
    pub relates_to: Annotation,
}

impl ReactionEventContent {
    /// Creates a new `ReactionEventContent` from the given annotation.
    ///
    /// You can also construct a `ReactionEventContent` from an annotation using `From` / `Into`.
    pub fn new(relates_to: Annotation) -> Self {
        Self { relates_to }
    }
}

impl From<Annotation> for ReactionEventContent {
    fn from(relates_to: Annotation) -> Self {
        Self::new(relates_to)
    }
}

#[cfg(test)]
mod tests {
    use assert_matches::assert_matches;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::ReactionEventContent;
    use crate::{event_id, events::relation::Annotation};

    #[test]
    fn deserialize() {
        let json = json!({
            "m.relates_to": {
                "rel_type": "m.annotation",
                "event_id": "$1598361704261elfgc:localhost",
                "key": "🦛",
            }
        });

        let relates_to = assert_matches!(
            from_json_value::<ReactionEventContent>(json),
            Ok(ReactionEventContent { relates_to }) => relates_to
        );
        assert_eq!(relates_to.event_id, "$1598361704261elfgc:localhost");
        assert_eq!(relates_to.key, "🦛");
    }

    #[test]
    fn serialize() {
        let content = ReactionEventContent::new(Annotation::new(
            event_id!("$my_reaction").to_owned(),
            "🏠".to_owned(),
        ));

        assert_eq!(
            to_json_value(&content).unwrap(),
            json!({
                "m.relates_to": {
                    "rel_type": "m.annotation",
                    "event_id": "$my_reaction",
                    "key": "🏠"
                }
            })
        );
    }
}
<|endoftext|>