<commit_before>use crate::options::NumfmtOptions;
use crate::units::{
    DisplayableSuffix, RawSuffix, Result, Suffix, Transform, Unit, IEC_BASES, SI_BASES,
};

/// Iterate over a line's fields, where each field is a contiguous sequence of
/// non-whitespace, optionally prefixed with one or more characters of leading
/// whitespace. Fields are returned as tuples of `(prefix, field)`.
///
/// # Examples:
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
///
/// assert_eq!(Some(("    ", "1234")), fields.next());
/// assert_eq!(Some((" ", "5")), fields.next());
/// assert_eq!(None, fields.next());
/// ```
///
/// Delimiters are included in the results; `prefix` will be empty only for
/// the first field of the line (including the case where the input line is
/// empty):
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
///
/// assert_eq!(Some(("", "first")), fields.next());
/// assert_eq!(Some((" ", "second")), fields.next());
///
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
///
/// assert_eq!(Some(("", "")), fields.next());
/// ```
pub struct WhitespaceSplitter<'a> {
    pub s: Option<&'a str>,
}

impl<'a> Iterator for WhitespaceSplitter<'a> {
    type Item = (&'a str, &'a str);

    /// Yield the next field in the input string as a tuple `(prefix, field)`.
    fn next(&mut self) -> Option<Self::Item> {
        let haystack = self.s?;

        let (prefix, field) = haystack.split_at(
            haystack
                .find(|c: char| !c.is_whitespace())
                .unwrap_or_else(|| haystack.len()),
        );

        let (field, rest) = field.split_at(
            field
                .find(|c: char| c.is_whitespace())
                .unwrap_or_else(|| field.len()),
        );

        self.s = if !rest.is_empty() { Some(rest) } else { None };

        Some((prefix, field))
    }
}

fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
    if s.is_empty() {
        return Err("invalid number: ‘’".to_string());
    }

    let with_i = s.ends_with('i');
    let mut iter = s.chars();
    if with_i {
        iter.next_back();
    }
    let suffix: Option<Suffix> = match iter.next_back() {
        Some('K') => Ok(Some((RawSuffix::K, with_i))),
        Some('M') => Ok(Some((RawSuffix::M, with_i))),
        Some('G') => Ok(Some((RawSuffix::G, with_i))),
        Some('T') => Ok(Some((RawSuffix::T, with_i))),
        Some('P') => Ok(Some((RawSuffix::P, with_i))),
        Some('E') => Ok(Some((RawSuffix::E, with_i))),
        Some('Z') => Ok(Some((RawSuffix::Z, with_i))),
        Some('Y') => Ok(Some((RawSuffix::Y, with_i))),
        Some('0'..='9') => Ok(None),
        _ => Err(format!("invalid suffix in input: ‘{}’", s)),
    }?;

    let suffix_len = match suffix {
        None => 0,
        Some((_, false)) => 1,
        Some((_, true)) => 2,
    };

    let number = s[..s.len() - suffix_len]
        .parse::<f64>()
        .map_err(|_| format!("invalid number: ‘{}’", s))?;

    Ok((number, suffix))
}

fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
    match (s, u) {
        (None, _) => Ok(i),
        (Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
            match raw_suffix {
                RawSuffix::K => Ok(i * 1e3),
                RawSuffix::M => Ok(i * 1e6),
                RawSuffix::G => Ok(i * 1e9),
                RawSuffix::T => Ok(i * 1e12),
                RawSuffix::P => Ok(i * 1e15),
                RawSuffix::E => Ok(i * 1e18),
                RawSuffix::Z => Ok(i * 1e21),
                RawSuffix::Y => Ok(i * 1e24),
            }
        }
        (Some((raw_suffix, false)), &Unit::Iec(false))
        | (Some((raw_suffix, true)), &Unit::Auto)
        | (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
            RawSuffix::K => Ok(i * IEC_BASES[1]),
            RawSuffix::M => Ok(i * IEC_BASES[2]),
            RawSuffix::G => Ok(i * IEC_BASES[3]),
            RawSuffix::T => Ok(i * IEC_BASES[4]),
            RawSuffix::P => Ok(i * IEC_BASES[5]),
            RawSuffix::E => Ok(i * IEC_BASES[6]),
            RawSuffix::Z => Ok(i * IEC_BASES[7]),
            RawSuffix::Y => Ok(i * IEC_BASES[8]),
        },
        (_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
    }
}

fn transform_from(s: &str, opts: &Transform) -> Result<f64> {
    let (i, suffix) = parse_suffix(s)?;

    remove_suffix(i, suffix, &opts.unit).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
}

/// Divide numerator by denominator, with ceiling.
///
/// If the result of the division is less than 10.0, truncate the result
/// to the next highest tenth.
///
/// Otherwise, truncate the result to the next highest whole number.
///
/// # Examples:
///
/// ```
/// use uu_numfmt::format::div_ceil;
///
/// assert_eq!(div_ceil(1.01, 1.0), 1.1);
/// assert_eq!(div_ceil(999.1, 1000.), 1.0);
/// assert_eq!(div_ceil(1001., 10.), 101.);
/// assert_eq!(div_ceil(9991., 10.), 1000.);
/// assert_eq!(div_ceil(-12.34, 1.0), -13.0);
/// assert_eq!(div_ceil(1000.0, -3.14), -319.0);
/// assert_eq!(div_ceil(-271828.0, -271.0), 1004.0);
/// ```
pub fn div_ceil(n: f64, d: f64) -> f64 {
    let v = n / (d / 10.0);
    let (v, sign) = if v < 0.0 { (v.abs(), -1.0) } else { (v, 1.0) };

    if v < 100.0 {
        v.ceil() / 10.0 * sign
    } else {
        (v / 10.0).ceil() * sign
    }
}

fn consider_suffix(n: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
    use crate::units::RawSuffix::*;

    let abs_n = n.abs();
    let suffixes = [K, M, G, T, P, E, Z, Y];

    let (bases, with_i) = match *u {
        Unit::Si => (&SI_BASES, false),
        Unit::Iec(with_i) => (&IEC_BASES, with_i),
        Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
        Unit::None => return Ok((n, None)),
    };

    let i = match abs_n {
        _ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
        _ if abs_n < bases[2] => 1,
        _ if abs_n < bases[3] => 2,
        _ if abs_n < bases[4] => 3,
        _ if abs_n < bases[5] => 4,
        _ if abs_n < bases[6] => 5,
        _ if abs_n < bases[7] => 6,
        _ if abs_n < bases[8] => 7,
        _ if abs_n < bases[9] => 8,
        _ => return Err("Number is too big and unsupported".to_string()),
    };

    let v = div_ceil(n, bases[i]);

    // check if rounding pushed us into the next base
    if v.abs() >= bases[1] {
        Ok((v / bases[1], Some((suffixes[i], with_i))))
    } else {
        Ok((v, Some((suffixes[i - 1], with_i))))
    }
}

fn transform_to(s: f64, opts: &Transform) -> Result<String> {
    let (i2, s) = consider_suffix(s, &opts.unit)?;
    Ok(match s {
        None => format!("{}", i2),
        Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
        Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
    })
}

fn format_string(
    source: &str,
    options: &NumfmtOptions,
    implicit_padding: Option<isize>,
) -> Result<String> {
    let number = transform_to(
        transform_from(source, &options.transform.from)?,
        &options.transform.to,
    )?;

    Ok(match implicit_padding.unwrap_or(options.padding) {
        p if p == 0 => number,
        p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
        p => format!("{:<padding$}", number, padding = p.abs() as usize),
    })
}

fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
    let delimiter = options.delimiter.as_ref().unwrap();

    for (n, field) in (1..).zip(s.split(delimiter)) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        // print delimiter before second and subsequent fields
        if n > 1 {
            print!("{}", delimiter);
        }

        if field_selected {
            print!("{}", format_string(&field.trim_start(), options, None)?);
        } else {
            // print unselected field without conversion
            print!("{}", field);
        }
    }

    println!();

    Ok(())
}

fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
    for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        if field_selected {
            let empty_prefix = prefix.is_empty();

            // print delimiter before second and subsequent fields
            let prefix = if n > 1 {
                print!(" ");
                &prefix[1..]
            } else {
                &prefix
            };

            let implicit_padding = if !empty_prefix && options.padding == 0 {
                Some((prefix.len() + field.len()) as isize)
            } else {
                None
            };

            print!("{}", format_string(&field, options, implicit_padding)?);
        } else {
            // print unselected field without conversion
            print!("{}{}", prefix, field);
        }
    }

    println!();

    Ok(())
}

/// Format a line of text according to the selected options.
///
/// Given a line of text `s`, split the line into fields, transform and format
/// any selected numeric fields, and print the result to stdout. Fields not
/// selected for conversion are passed through unmodified.
pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
    match &options.delimiter {
        Some(_) => format_and_print_delimited(s, options),
        None => format_and_print_whitespace(s, options),
    }
}
<commit_msg>refactor/numfmt ~ fix `cargo clippy` complaint (clippy::needless_borrow)<commit_after>use crate::options::NumfmtOptions;
use crate::units::{
    DisplayableSuffix, RawSuffix, Result, Suffix, Transform, Unit, IEC_BASES, SI_BASES,
};

/// Iterate over a line's fields, where each field is a contiguous sequence of
/// non-whitespace, optionally prefixed with one or more characters of leading
/// whitespace. Fields are returned as tuples of `(prefix, field)`.
///
/// # Examples:
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
///
/// assert_eq!(Some(("    ", "1234")), fields.next());
/// assert_eq!(Some((" ", "5")), fields.next());
/// assert_eq!(None, fields.next());
/// ```
///
/// Delimiters are included in the results; `prefix` will be empty only for
/// the first field of the line (including the case where the input line is
/// empty):
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
///
/// assert_eq!(Some(("", "first")), fields.next());
/// assert_eq!(Some((" ", "second")), fields.next());
///
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
///
/// assert_eq!(Some(("", "")), fields.next());
/// ```
pub struct WhitespaceSplitter<'a> {
    pub s: Option<&'a str>,
}

impl<'a> Iterator for WhitespaceSplitter<'a> {
    type Item = (&'a str, &'a str);

    /// Yield the next field in the input string as a tuple `(prefix, field)`.
    fn next(&mut self) -> Option<Self::Item> {
        let haystack = self.s?;

        let (prefix, field) = haystack.split_at(
            haystack
                .find(|c: char| !c.is_whitespace())
                .unwrap_or_else(|| haystack.len()),
        );

        let (field, rest) = field.split_at(
            field
                .find(|c: char| c.is_whitespace())
                .unwrap_or_else(|| field.len()),
        );

        self.s = if !rest.is_empty() { Some(rest) } else { None };

        Some((prefix, field))
    }
}

fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
    if s.is_empty() {
        return Err("invalid number: ‘’".to_string());
    }

    let with_i = s.ends_with('i');
    let mut iter = s.chars();
    if with_i {
        iter.next_back();
    }
    let suffix: Option<Suffix> = match iter.next_back() {
        Some('K') => Ok(Some((RawSuffix::K, with_i))),
        Some('M') => Ok(Some((RawSuffix::M, with_i))),
        Some('G') => Ok(Some((RawSuffix::G, with_i))),
        Some('T') => Ok(Some((RawSuffix::T, with_i))),
        Some('P') => Ok(Some((RawSuffix::P, with_i))),
        Some('E') => Ok(Some((RawSuffix::E, with_i))),
        Some('Z') => Ok(Some((RawSuffix::Z, with_i))),
        Some('Y') => Ok(Some((RawSuffix::Y, with_i))),
        Some('0'..='9') => Ok(None),
        _ => Err(format!("invalid suffix in input: ‘{}’", s)),
    }?;

    let suffix_len = match suffix {
        None => 0,
        Some((_, false)) => 1,
        Some((_, true)) => 2,
    };

    let number = s[..s.len() - suffix_len]
        .parse::<f64>()
        .map_err(|_| format!("invalid number: ‘{}’", s))?;

    Ok((number, suffix))
}

fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
    match (s, u) {
        (None, _) => Ok(i),
        (Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
            match raw_suffix {
                RawSuffix::K => Ok(i * 1e3),
                RawSuffix::M => Ok(i * 1e6),
                RawSuffix::G => Ok(i * 1e9),
                RawSuffix::T => Ok(i * 1e12),
                RawSuffix::P => Ok(i * 1e15),
                RawSuffix::E => Ok(i * 1e18),
                RawSuffix::Z => Ok(i * 1e21),
                RawSuffix::Y => Ok(i * 1e24),
            }
        }
        (Some((raw_suffix, false)), &Unit::Iec(false))
        | (Some((raw_suffix, true)), &Unit::Auto)
        | (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
            RawSuffix::K => Ok(i * IEC_BASES[1]),
            RawSuffix::M => Ok(i * IEC_BASES[2]),
            RawSuffix::G => Ok(i * IEC_BASES[3]),
            RawSuffix::T => Ok(i * IEC_BASES[4]),
            RawSuffix::P => Ok(i * IEC_BASES[5]),
            RawSuffix::E => Ok(i * IEC_BASES[6]),
            RawSuffix::Z => Ok(i * IEC_BASES[7]),
            RawSuffix::Y => Ok(i * IEC_BASES[8]),
        },
        (_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
    }
}

fn transform_from(s: &str, opts: &Transform) -> Result<f64> {
    let (i, suffix) = parse_suffix(s)?;

    remove_suffix(i, suffix, &opts.unit).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
}

/// Divide numerator by denominator, with ceiling.
///
/// If the result of the division is less than 10.0, truncate the result
/// to the next highest tenth.
///
/// Otherwise, truncate the result to the next highest whole number.
///
/// # Examples:
///
/// ```
/// use uu_numfmt::format::div_ceil;
///
/// assert_eq!(div_ceil(1.01, 1.0), 1.1);
/// assert_eq!(div_ceil(999.1, 1000.), 1.0);
/// assert_eq!(div_ceil(1001., 10.), 101.);
/// assert_eq!(div_ceil(9991., 10.), 1000.);
/// assert_eq!(div_ceil(-12.34, 1.0), -13.0);
/// assert_eq!(div_ceil(1000.0, -3.14), -319.0);
/// assert_eq!(div_ceil(-271828.0, -271.0), 1004.0);
/// ```
pub fn div_ceil(n: f64, d: f64) -> f64 {
    let v = n / (d / 10.0);
    let (v, sign) = if v < 0.0 { (v.abs(), -1.0) } else { (v, 1.0) };

    if v < 100.0 {
        v.ceil() / 10.0 * sign
    } else {
        (v / 10.0).ceil() * sign
    }
}

fn consider_suffix(n: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
    use crate::units::RawSuffix::*;

    let abs_n = n.abs();
    let suffixes = [K, M, G, T, P, E, Z, Y];

    let (bases, with_i) = match *u {
        Unit::Si => (&SI_BASES, false),
        Unit::Iec(with_i) => (&IEC_BASES, with_i),
        Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
        Unit::None => return Ok((n, None)),
    };

    let i = match abs_n {
        _ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
        _ if abs_n < bases[2] => 1,
        _ if abs_n < bases[3] => 2,
        _ if abs_n < bases[4] => 3,
        _ if abs_n < bases[5] => 4,
        _ if abs_n < bases[6] => 5,
        _ if abs_n < bases[7] => 6,
        _ if abs_n < bases[8] => 7,
        _ if abs_n < bases[9] => 8,
        _ => return Err("Number is too big and unsupported".to_string()),
    };

    let v = div_ceil(n, bases[i]);

    // check if rounding pushed us into the next base
    if v.abs() >= bases[1] {
        Ok((v / bases[1], Some((suffixes[i], with_i))))
    } else {
        Ok((v, Some((suffixes[i - 1], with_i))))
    }
}

fn transform_to(s: f64, opts: &Transform) -> Result<String> {
    let (i2, s) = consider_suffix(s, &opts.unit)?;
    Ok(match s {
        None => format!("{}", i2),
        Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
        Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
    })
}

fn format_string(
    source: &str,
    options: &NumfmtOptions,
    implicit_padding: Option<isize>,
) -> Result<String> {
    let number = transform_to(
        transform_from(source, &options.transform.from)?,
        &options.transform.to,
    )?;

    Ok(match implicit_padding.unwrap_or(options.padding) {
        p if p == 0 => number,
        p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
        p => format!("{:<padding$}", number, padding = p.abs() as usize),
    })
}

fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
    let delimiter = options.delimiter.as_ref().unwrap();

    for (n, field) in (1..).zip(s.split(delimiter)) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        // print delimiter before second and subsequent fields
        if n > 1 {
            print!("{}", delimiter);
        }

        if field_selected {
            print!("{}", format_string(field.trim_start(), options, None)?);
        } else {
            // print unselected field without conversion
            print!("{}", field);
        }
    }

    println!();

    Ok(())
}

fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
    for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        if field_selected {
            let empty_prefix = prefix.is_empty();

            // print delimiter before second and subsequent fields
            let prefix = if n > 1 {
                print!(" ");
                &prefix[1..]
            } else {
                &prefix
            };

            let implicit_padding = if !empty_prefix && options.padding == 0 {
                Some((prefix.len() + field.len()) as isize)
            } else {
                None
            };

            print!("{}", format_string(field, options, implicit_padding)?);
        } else {
            // print unselected field without conversion
            print!("{}{}", prefix, field);
        }
    }

    println!();

    Ok(())
}

/// Format a line of text according to the selected options.
///
/// Given a line of text `s`, split the line into fields, transform and format
/// any selected numeric fields, and print the result to stdout. Fields not
/// selected for conversion are passed through unmodified.
pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
    match &options.delimiter {
        Some(_) => format_and_print_delimited(s, options),
        None => format_and_print_whitespace(s, options),
    }
}
<|endoftext|>


<commit_before>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(drop_types_in_const)]
#![feature(associated_consts)]
#![feature(const_fn)]
#![feature(type_ascription)]
#![feature(pub_restricted)]
#![feature(lookup_host)]
#![feature(plugin)]

#![plugin(pear_codegen)]

//! # Rocket - Core API Documentation
//!
//! Hello, and welcome to the core Rocket API documentation!
//!
//! This API documentation is highly technical and is purely a reference.
//! There's an [overview](https://rocket.rs/overview) of Rocket on the main site
//! as well as a [full, detailed guide](https://rocket.rs/guide). If you'd like
//! pointers on getting started, see the
//! [quickstart](https://rocket.rs/guide/quickstart) or [getting
//! started](https://rocket.rs/guide/getting-started) chapters of the guide.
//!
//! You may also be interested in looking at the [contrib API
//! documentation](/rocket_contrib), which contains JSON and templating
//! support, among other features.
//!
//! ## Libraries
//!
//! Rocket's functionality is split into three crates:
//!
//!   1. [Core](/rocket) - The core library. Needed by every Rocket application.
//!   2. [Codegen](/rocket_codegen) - Core code generation plugin. Should always
//!      be used alongsize `rocket`, though it's not necessary.
//!   3. [Contrib](/rocket_contrib) - Provides useful functionality for many
//!      Rocket applications. Completely optional.
//!
//! ## Usage
//!
//! The sanctioned way to use Rocket is via the code generation plugin. This
//! makes Rocket easier and safer to use and allows a somewhat stable API as
//! Rocket matures. To use Rocket with the code generation plugin in your
//! Cargo-based project, add the following to `Cargo.toml`:
//!
//! ```rust,ignore
//! [dependencies]
//! rocket = "*"
//! rocket_codegen = "*"
//! ```
//!
//! If you'll be deploying your project to [crates.io](https://crates.io),
//! you'll need to change the "*" to the current version of Rocket.
//!
//! Then, add the following to the top of your `main.rs` file:
//!
//! ```rust
//! #![feature(plugin)]
//! # #![allow(unused_attributes)]
//! #![plugin(rocket_codegen)]
//!
//! extern crate rocket;
//! ```
//!
//! See the [guide](https://rocket.rs/guide) for more information on how to
//! write Rocket applications. Here's a simple example to get you started:
//!
//! ```rust
//! #![feature(plugin)]
//! #![plugin(rocket_codegen)]
//!
//! extern crate rocket;
//!
//! #[get("/")]
//! fn hello() -> &'static str {
//!     "Hello, world!"
//! }
//!
//! fn main() {
//! # if false { // We don't actually want to launch the server in an example.
//!     rocket::ignite().mount("/", routes![hello]).launch();
//! # }
//! }
//! ```
//!
//! ## Configuration
//!
//! Rocket and Rocket libraries are configured via the `Rocket.toml` file and/or
//! `ROCKET_{PARAM}` environment variables. For more information on how to
//! configure Rocket, see the [configuration
//! section](https://rocket.rs/guide/overview/#configuration) of the guide as
//! well as the [config](/rocket/config) module documentation.
//!
//! ## Testing
//!
//! Rocket includes a small testing library that can be used to test your Rocket
//! application. For information on how to test your Rocket applications, see
//! the [testing module](/rocket/testing) documentation.
//!

#[macro_use] extern crate log;
#[macro_use] extern crate pear;
extern crate term_painter;
extern crate hyper;
extern crate url;
extern crate toml;
extern crate num_cpus;
extern crate state;
extern crate cookie;
extern crate time;
extern crate memchr;
extern crate base64;
extern crate smallvec;

#[cfg(test)] #[macro_use] extern crate lazy_static;

#[doc(hidden)] #[macro_use] pub mod logger;
#[cfg(any(test, feature = "testing"))] pub mod testing;
pub mod http;
pub mod request;
pub mod response;
pub mod outcome;
pub mod config;
pub mod data;
pub mod handler;
pub mod error;

mod router;
mod rocket;
mod codegen;
mod catcher;
mod ext;

#[doc(inline)] pub use response::Response;
#[doc(inline)] pub use handler::{Handler, ErrorHandler};
#[doc(inline)] pub use logger::LoggingLevel;
#[doc(hidden)] pub use codegen::{StaticRouteInfo, StaticCatchInfo};
#[doc(inline)] pub use outcome::Outcome;
#[doc(inline)] pub use data::Data;
pub use router::Route;
pub use request::{Request, State};
pub use error::{Error, LaunchError};
pub use catcher::Catcher;
pub use rocket::Rocket;

/// Alias to [Rocket::ignite()](/rocket/struct.Rocket.html#method.ignite).
/// Creates a new instance of `Rocket`.
pub fn ignite() -> Rocket {
    Rocket::ignite()
}

/// Alias to [Rocket::custom()](/rocket/struct.Rocket.html#method.custom).
/// Creates a new instance of `Rocket` with a custom configuration.
pub fn custom(config: config::Config, log: bool) -> Rocket {
    Rocket::custom(config, log)
}
<commit_msg>Remove pub_restricted feature: it's stable!<commit_after>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(drop_types_in_const)]
#![feature(associated_consts)]
#![feature(const_fn)]
#![feature(type_ascription)]
#![feature(lookup_host)]
#![feature(plugin)]

#![plugin(pear_codegen)]

//! # Rocket - Core API Documentation
//!
//! Hello, and welcome to the core Rocket API documentation!
//!
//! This API documentation is highly technical and is purely a reference.
//! There's an [overview](https://rocket.rs/overview) of Rocket on the main site
//! as well as a [full, detailed guide](https://rocket.rs/guide). If you'd like
//! pointers on getting started, see the
//! [quickstart](https://rocket.rs/guide/quickstart) or [getting
//! started](https://rocket.rs/guide/getting-started) chapters of the guide.
//!
//! You may also be interested in looking at the [contrib API
//! documentation](/rocket_contrib), which contains JSON and templating
//! support, among other features.
//!
//! ## Libraries
//!
//! Rocket's functionality is split into three crates:
//!
//!   1. [Core](/rocket) - The core library. Needed by every Rocket application.
//!   2. [Codegen](/rocket_codegen) - Core code generation plugin. Should always
//!      be used alongsize `rocket`, though it's not necessary.
//!   3. [Contrib](/rocket_contrib) - Provides useful functionality for many
//!      Rocket applications. Completely optional.
//!
//! ## Usage
//!
//! The sanctioned way to use Rocket is via the code generation plugin. This
//! makes Rocket easier and safer to use and allows a somewhat stable API as
//! Rocket matures. To use Rocket with the code generation plugin in your
//! Cargo-based project, add the following to `Cargo.toml`:
//!
//! ```rust,ignore
//! [dependencies]
//! rocket = "*"
//! rocket_codegen = "*"
//! ```
//!
//! If you'll be deploying your project to [crates.io](https://crates.io),
//! you'll need to change the "*" to the current version of Rocket.
//!
//! Then, add the following to the top of your `main.rs` file:
//!
//! ```rust
//! #![feature(plugin)]
//! # #![allow(unused_attributes)]
//! #![plugin(rocket_codegen)]
//!
//! extern crate rocket;
//! ```
//!
//! See the [guide](https://rocket.rs/guide) for more information on how to
//! write Rocket applications. Here's a simple example to get you started:
//!
//! ```rust
//! #![feature(plugin)]
//! #![plugin(rocket_codegen)]
//!
//! extern crate rocket;
//!
//! #[get("/")]
//! fn hello() -> &'static str {
//!     "Hello, world!"
//! }
//!
//! fn main() {
//! # if false { // We don't actually want to launch the server in an example.
//!     rocket::ignite().mount("/", routes![hello]).launch();
//! # }
//! }
//! ```
//!
//! ## Configuration
//!
//! Rocket and Rocket libraries are configured via the `Rocket.toml` file and/or
//! `ROCKET_{PARAM}` environment variables. For more information on how to
//! configure Rocket, see the [configuration
//! section](https://rocket.rs/guide/overview/#configuration) of the guide as
//! well as the [config](/rocket/config) module documentation.
//!
//! ## Testing
//!
//! Rocket includes a small testing library that can be used to test your Rocket
//! application. For information on how to test your Rocket applications, see
//! the [testing module](/rocket/testing) documentation.
//!

#[macro_use] extern crate log;
#[macro_use] extern crate pear;
extern crate term_painter;
extern crate hyper;
extern crate url;
extern crate toml;
extern crate num_cpus;
extern crate state;
extern crate cookie;
extern crate time;
extern crate memchr;
extern crate base64;
extern crate smallvec;

#[cfg(test)] #[macro_use] extern crate lazy_static;

#[doc(hidden)] #[macro_use] pub mod logger;
#[cfg(any(test, feature = "testing"))] pub mod testing;
pub mod http;
pub mod request;
pub mod response;
pub mod outcome;
pub mod config;
pub mod data;
pub mod handler;
pub mod error;

mod router;
mod rocket;
mod codegen;
mod catcher;
mod ext;

#[doc(inline)] pub use response::Response;
#[doc(inline)] pub use handler::{Handler, ErrorHandler};
#[doc(inline)] pub use logger::LoggingLevel;
#[doc(hidden)] pub use codegen::{StaticRouteInfo, StaticCatchInfo};
#[doc(inline)] pub use outcome::Outcome;
#[doc(inline)] pub use data::Data;
pub use router::Route;
pub use request::{Request, State};
pub use error::{Error, LaunchError};
pub use catcher::Catcher;
pub use rocket::Rocket;

/// Alias to [Rocket::ignite()](/rocket/struct.Rocket.html#method.ignite).
/// Creates a new instance of `Rocket`.
pub fn ignite() -> Rocket {
    Rocket::ignite()
}

/// Alias to [Rocket::custom()](/rocket/struct.Rocket.html#method.custom).
/// Creates a new instance of `Rocket` with a custom configuration.
pub fn custom(config: config::Config, log: bool) -> Rocket {
    Rocket::custom(config, log)
}
<|endoftext|>


<commit_before>use core::ptr;

use super::node::{marker, ForceResult::*, Handle, NodeRef};
use super::unwrap_unchecked;

impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
    /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
    /// on the right side, which is either in the same leaf node or in an ancestor node.
    /// If the leaf edge is the last one in the tree, returns [`Result::Err`] with the root node.
    pub fn next_kv(
        self,
    ) -> Result<
        Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
        NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
    > {
        let mut edge = self.forget_node_type();
        loop {
            edge = match edge.right_kv() {
                Ok(internal_kv) => return Ok(internal_kv),
                Err(last_edge) => match last_edge.into_node().ascend() {
                    Ok(parent_edge) => parent_edge.forget_node_type(),
                    Err(root) => return Err(root),
                },
            }
        }
    }

    /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
    /// on the left side, which is either in the same leaf node or in an ancestor node.
    /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
    pub fn next_back_kv(
        self,
    ) -> Result<
        Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
        NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
    > {
        let mut edge = self.forget_node_type();
        loop {
            edge = match edge.left_kv() {
                Ok(internal_kv) => return Ok(internal_kv),
                Err(last_edge) => match last_edge.into_node().ascend() {
                    Ok(parent_edge) => parent_edge.forget_node_type(),
                    Err(root) => return Err(root),
                },
            }
        }
    }
}

macro_rules! def_next_kv_uncheched_dealloc {
    { unsafe fn $name:ident : $adjacent_kv:ident } => {
        /// Given a leaf edge handle into an owned tree, returns a handle to the next KV,
        /// while deallocating any node left behind.
        /// Unsafe for two reasons:
        /// - The caller must ensure that the leaf edge is not the last one in the tree.
        /// - The node pointed at by the given handle, and its ancestors, may be deallocated,
        ///   while the reference to those nodes in the surviving ancestors is left dangling;
        ///   thus using the returned handle to navigate further is dangerous.
        unsafe fn $name <K, V>(
            leaf_edge: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
        ) -> Handle<NodeRef<marker::Owned, K, V, marker::LeafOrInternal>, marker::KV> {
            let mut edge = leaf_edge.forget_node_type();
            loop {
                edge = match edge.$adjacent_kv() {
                    Ok(internal_kv) => return internal_kv,
                    Err(last_edge) => {
                        unsafe {
                            let parent_edge = last_edge.into_node().deallocate_and_ascend();
                            unwrap_unchecked(parent_edge).forget_node_type()
                        }
                    }
                }
            }
        }
    };
}

def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv}
def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}

/// This replaces the value behind the `v` unique reference by calling the
/// relevant function.
///
/// Safety: The change closure must not panic.
#[inline]
unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
    let value = unsafe { ptr::read(v) };
    let (new_value, ret) = change(value);
    unsafe {
        ptr::write(v, new_value);
    }
    ret
}

impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
    pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
        unsafe {
            replace(self, |leaf_edge| {
                let kv = leaf_edge.next_kv();
                let kv = unwrap_unchecked(kv.ok());
                (kv.next_leaf_edge(), kv.into_kv())
            })
        }
    }

    /// Moves the leaf edge handle to the previous leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
    pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
        unsafe {
            replace(self, |leaf_edge| {
                let kv = leaf_edge.next_back_kv();
                let kv = unwrap_unchecked(kv.ok());
                (kv.next_back_leaf_edge(), kv.into_kv())
            })
        }
    }
}

impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the last one in the tree.
    /// - Using the updated handle may well invalidate the returned references.
    pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
        unsafe {
            let kv = replace(self, |leaf_edge| {
                let kv = leaf_edge.next_kv();
                let kv = unwrap_unchecked(kv.ok());
                (ptr::read(&kv).next_leaf_edge(), kv)
            });
            // Doing the descend (and perhaps another move) invalidates the references
            // returned by `into_kv_mut`, so we have to do this last.
            kv.into_kv_mut()
        }
    }

    /// Moves the leaf edge handle to the previous leaf and returns references to the
    /// key and value in between.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the first one in the tree.
    /// - Using the updated handle may well invalidate the returned references.
    pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
        unsafe {
            let kv = replace(self, |leaf_edge| {
                let kv = leaf_edge.next_back_kv();
                let kv = unwrap_unchecked(kv.ok());
                (ptr::read(&kv).next_back_leaf_edge(), kv)
            });
            // Doing the descend (and perhaps another move) invalidates the references
            // returned by `into_kv_mut`, so we have to do this last.
            kv.into_kv_mut()
        }
    }
}

impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns the key and value
    /// in between, while deallocating any node left behind.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the last one in the tree
    ///   and is not a handle previously resulting from counterpart `next_back_unchecked`.
    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
    ///   if the leaf edge is the last edge of a node, that node and possibly ancestors
    ///   will be deallocated, while the reference to those nodes in the surviving ancestor
    ///   is left dangling.
    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
    ///   call this method again subject to both preconditions listed in the first point,
    ///   or call counterpart `next_back_unchecked` subject to its preconditions.
    pub unsafe fn next_unchecked(&mut self) -> (K, V) {
        unsafe {
            replace(self, |leaf_edge| {
                let kv = next_kv_unchecked_dealloc(leaf_edge);
                let k = ptr::read(kv.reborrow().into_kv().0);
                let v = ptr::read(kv.reborrow().into_kv().1);
                (kv.next_leaf_edge(), (k, v))
            })
        }
    }

    /// Moves the leaf edge handle to the previous leaf edge and returns the key
    /// and value in between, while deallocating any node left behind.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the first one in the tree
    ///   and is not a handle previously resulting from counterpart `next_unchecked`.
    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
    ///   if the leaf edge is the first edge of a node, that node and possibly ancestors
    ///   will be deallocated, while the reference to those nodes in the surviving ancestor
    ///   is left dangling.
    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
    ///   call this method again subject to both preconditions listed in the first point,
    ///   or call counterpart `next_unchecked` subject to its preconditions.
    pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
        unsafe {
            replace(self, |leaf_edge| {
                let kv = next_back_kv_unchecked_dealloc(leaf_edge);
                let k = ptr::read(kv.reborrow().into_kv().0);
                let v = ptr::read(kv.reborrow().into_kv().1);
                (kv.next_back_leaf_edge(), (k, v))
            })
        }
    }
}

impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
    /// Returns the leftmost leaf edge in or underneath a node - in other words, the edge
    /// you need first when navigating forward (or last when navigating backward).
    #[inline]
    pub fn first_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        let mut node = self;
        loop {
            match node.force() {
                Leaf(leaf) => return leaf.first_edge(),
                Internal(internal) => node = internal.first_edge().descend(),
            }
        }
    }

    /// Returns the rightmost leaf edge in or underneath a node - in other words, the edge
    /// you need last when navigating forward (or first when navigating backward).
    #[inline]
    pub fn last_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        let mut node = self;
        loop {
            match node.force() {
                Leaf(leaf) => return leaf.last_edge(),
                Internal(internal) => node = internal.last_edge().descend(),
            }
        }
    }
}

impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
    /// Returns the leaf edge closest to a KV for forward navigation.
    pub fn next_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        match self.force() {
            Leaf(leaf_kv) => leaf_kv.right_edge(),
            Internal(internal_kv) => {
                let next_internal_edge = internal_kv.right_edge();
                next_internal_edge.descend().first_leaf_edge()
            }
        }
    }

    /// Returns the leaf edge closest to a KV for backward navigation.
    pub fn next_back_leaf_edge(
        self,
    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        match self.force() {
            Leaf(leaf_kv) => leaf_kv.left_edge(),
            Internal(internal_kv) => {
                let next_internal_edge = internal_kv.left_edge();
                next_internal_edge.descend().last_leaf_edge()
            }
        }
    }
}
<commit_msg>Auto merge of #75071 - ssomers:btree_cleanup_5, r=Mark-Simulacrum<commit_after>use core::intrinsics;
use core::mem;
use core::ptr;

use super::node::{marker, ForceResult::*, Handle, NodeRef};
use super::unwrap_unchecked;

impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
    /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
    /// on the right side, which is either in the same leaf node or in an ancestor node.
    /// If the leaf edge is the last one in the tree, returns [`Result::Err`] with the root node.
    pub fn next_kv(
        self,
    ) -> Result<
        Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
        NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
    > {
        let mut edge = self.forget_node_type();
        loop {
            edge = match edge.right_kv() {
                Ok(internal_kv) => return Ok(internal_kv),
                Err(last_edge) => match last_edge.into_node().ascend() {
                    Ok(parent_edge) => parent_edge.forget_node_type(),
                    Err(root) => return Err(root),
                },
            }
        }
    }

    /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
    /// on the left side, which is either in the same leaf node or in an ancestor node.
    /// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
    pub fn next_back_kv(
        self,
    ) -> Result<
        Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
        NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
    > {
        let mut edge = self.forget_node_type();
        loop {
            edge = match edge.left_kv() {
                Ok(internal_kv) => return Ok(internal_kv),
                Err(last_edge) => match last_edge.into_node().ascend() {
                    Ok(parent_edge) => parent_edge.forget_node_type(),
                    Err(root) => return Err(root),
                },
            }
        }
    }
}

macro_rules! def_next_kv_uncheched_dealloc {
    { unsafe fn $name:ident : $adjacent_kv:ident } => {
        /// Given a leaf edge handle into an owned tree, returns a handle to the next KV,
        /// while deallocating any node left behind.
        /// Unsafe for two reasons:
        /// - The caller must ensure that the leaf edge is not the last one in the tree.
        /// - The node pointed at by the given handle, and its ancestors, may be deallocated,
        ///   while the reference to those nodes in the surviving ancestors is left dangling;
        ///   thus using the returned handle to navigate further is dangerous.
        unsafe fn $name <K, V>(
            leaf_edge: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
        ) -> Handle<NodeRef<marker::Owned, K, V, marker::LeafOrInternal>, marker::KV> {
            let mut edge = leaf_edge.forget_node_type();
            loop {
                edge = match edge.$adjacent_kv() {
                    Ok(internal_kv) => return internal_kv,
                    Err(last_edge) => {
                        unsafe {
                            let parent_edge = last_edge.into_node().deallocate_and_ascend();
                            unwrap_unchecked(parent_edge).forget_node_type()
                        }
                    }
                }
            }
        }
    };
}

def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv}
def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}

/// This replaces the value behind the `v` unique reference by calling the
/// relevant function, and returns a result obtained along the way.
///
/// If a panic occurs in the `change` closure, the entire process will be aborted.
#[inline]
fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
    struct PanicGuard;
    impl Drop for PanicGuard {
        fn drop(&mut self) {
            intrinsics::abort()
        }
    }
    let guard = PanicGuard;
    let value = unsafe { ptr::read(v) };
    let (new_value, ret) = change(value);
    unsafe {
        ptr::write(v, new_value);
    }
    mem::forget(guard);
    ret
}

impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
    pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
        replace(self, |leaf_edge| {
            let kv = leaf_edge.next_kv();
            let kv = unsafe { unwrap_unchecked(kv.ok()) };
            (kv.next_leaf_edge(), kv.into_kv())
        })
    }

    /// Moves the leaf edge handle to the previous leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
    pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
        replace(self, |leaf_edge| {
            let kv = leaf_edge.next_back_kv();
            let kv = unsafe { unwrap_unchecked(kv.ok()) };
            (kv.next_back_leaf_edge(), kv.into_kv())
        })
    }
}

impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns references to the
    /// key and value in between.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the last one in the tree.
    /// - Using the updated handle may well invalidate the returned references.
    pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
        let kv = replace(self, |leaf_edge| {
            let kv = leaf_edge.next_kv();
            let kv = unsafe { unwrap_unchecked(kv.ok()) };
            (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
        });
        // Doing the descend (and perhaps another move) invalidates the references
        // returned by `into_kv_mut`, so we have to do this last.
        kv.into_kv_mut()
    }

    /// Moves the leaf edge handle to the previous leaf and returns references to the
    /// key and value in between.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the first one in the tree.
    /// - Using the updated handle may well invalidate the returned references.
    pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
        let kv = replace(self, |leaf_edge| {
            let kv = leaf_edge.next_back_kv();
            let kv = unsafe { unwrap_unchecked(kv.ok()) };
            (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
        });
        // Doing the descend (and perhaps another move) invalidates the references
        // returned by `into_kv_mut`, so we have to do this last.
        kv.into_kv_mut()
    }
}

impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
    /// Moves the leaf edge handle to the next leaf edge and returns the key and value
    /// in between, while deallocating any node left behind.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the last one in the tree
    ///   and is not a handle previously resulting from counterpart `next_back_unchecked`.
    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
    ///   if the leaf edge is the last edge of a node, that node and possibly ancestors
    ///   will be deallocated, while the reference to those nodes in the surviving ancestor
    ///   is left dangling.
    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
    ///   call this method again subject to both preconditions listed in the first point,
    ///   or call counterpart `next_back_unchecked` subject to its preconditions.
    pub unsafe fn next_unchecked(&mut self) -> (K, V) {
        replace(self, |leaf_edge| {
            let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) };
            let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
            let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
            (kv.next_leaf_edge(), (k, v))
        })
    }

    /// Moves the leaf edge handle to the previous leaf edge and returns the key
    /// and value in between, while deallocating any node left behind.
    /// Unsafe for two reasons:
    /// - The caller must ensure that the leaf edge is not the first one in the tree
    ///   and is not a handle previously resulting from counterpart `next_unchecked`.
    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
    ///   if the leaf edge is the first edge of a node, that node and possibly ancestors
    ///   will be deallocated, while the reference to those nodes in the surviving ancestor
    ///   is left dangling.
    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
    ///   call this method again subject to both preconditions listed in the first point,
    ///   or call counterpart `next_unchecked` subject to its preconditions.
    pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
        replace(self, |leaf_edge| {
            let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) };
            let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
            let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
            (kv.next_back_leaf_edge(), (k, v))
        })
    }
}

impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
    /// Returns the leftmost leaf edge in or underneath a node - in other words, the edge
    /// you need first when navigating forward (or last when navigating backward).
    #[inline]
    pub fn first_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        let mut node = self;
        loop {
            match node.force() {
                Leaf(leaf) => return leaf.first_edge(),
                Internal(internal) => node = internal.first_edge().descend(),
            }
        }
    }

    /// Returns the rightmost leaf edge in or underneath a node - in other words, the edge
    /// you need last when navigating forward (or first when navigating backward).
    #[inline]
    pub fn last_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        let mut node = self;
        loop {
            match node.force() {
                Leaf(leaf) => return leaf.last_edge(),
                Internal(internal) => node = internal.last_edge().descend(),
            }
        }
    }
}

impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
    /// Returns the leaf edge closest to a KV for forward navigation.
    pub fn next_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        match self.force() {
            Leaf(leaf_kv) => leaf_kv.right_edge(),
            Internal(internal_kv) => {
                let next_internal_edge = internal_kv.right_edge();
                next_internal_edge.descend().first_leaf_edge()
            }
        }
    }

    /// Returns the leaf edge closest to a KV for backward navigation.
    pub fn next_back_leaf_edge(
        self,
    ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
        match self.force() {
            Leaf(leaf_kv) => leaf_kv.left_edge(),
            Internal(internal_kv) => {
                let next_internal_edge = internal_kv.left_edge();
                next_internal_edge.descend().last_leaf_edge()
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate itertools;

use test::{black_box};
use itertools::Stride;
use itertools::Itertools;

#[cfg(feature = "unstable")]
use itertools::{ZipTrusted};

use itertools::ZipSlices;

use std::iter::repeat;
use std::cmp;

#[bench]
fn slice_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter() {
        test::black_box(elt);
    })
}

#[bench]
fn slice_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter().rev() {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1) {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1).rev() {
        test::black_box(elt);
    })
}

#[bench]
fn zip_default_zip(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in xs.iter().zip(&ys) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_default_zip3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) {
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
        }
    })
}

/*
#[bench]
fn zip_slices_ziptuple(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| {
        let xs = black_box(&xs);
        let ys = black_box(&ys);
        for (&x, &y) in Zip::new((xs, ys)) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}
*/

#[bench]
fn zip_slices(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in ZipSlices::new(&xs, &ys) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_slices_mut(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let mut ys = black_box(ys);

    b.iter(|| {
        for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[cfg(feature = "unstable")]
#[bench]
fn ziptrusted(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in ZipTrusted::new((xs.iter(), ys.iter())) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[cfg(feature = "unstable")]
#[bench]
fn ziptrusted3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        for (&x, &y, &z) in ZipTrusted::new((xs.iter(), ys.iter(), zs.iter())) {
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
        }
    })
}

#[bench]
fn zip_checked_counted_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        // Must slice to equal lengths, and then bounds checks are eliminated!
        let len = cmp::min(xs.len(), ys.len());
        let xs = &xs[..len];
        let ys = &ys[..len];

        for i in 0..len {
            let x = xs[i];
            let y = ys[i];
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_unchecked_counted_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        let len = cmp::min(xs.len(), ys.len());
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            }
        }
    })
}

#[bench]
fn zip_unchecked_counted_loop3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            let z = *zs.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
            }
        }
    })
}

#[bench]
fn group_by_lazy_1(b: &mut test::Bencher) {
    let mut data = vec![0; 1024];
    for (index, elt) in data.iter_mut().enumerate() {
        *elt = index / 10;
    }

    let data = test::black_box(data);

    b.iter(|| {
        for (_key, group) in &data.iter().group_by_lazy(|elt| **elt) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn group_by_lazy_2(b: &mut test::Bencher) {
    let mut data = vec![0; 1024];
    for (index, elt) in data.iter_mut().enumerate() {
        *elt = index / 2;
    }

    let data = test::black_box(data);

    b.iter(|| {
        for (_key, group) in &data.iter().group_by_lazy(|elt| **elt) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn slice_chunks(b: &mut test::Bencher) {
    let data = vec![0; 1024];

    let data = test::black_box(data);
    let sz = test::black_box(10);

    b.iter(|| {
        for group in data.chunks(sz) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn chunks_lazy_1(b: &mut test::Bencher) {
    let data = vec![0; 1024];

    let data = test::black_box(data);
    let sz = test::black_box(10);

    b.iter(|| {
        for group in &data.iter().chunks_lazy(sz) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn equal(b: &mut test::Bencher) {
    let data = vec![7; 1024];
    let l = data.len();
    b.iter(|| {
        let a = test::black_box(&data[1..]);
        let b = test::black_box(&data[..l - 1]);
        itertools::equal(a, b)
    })
}
<commit_msg>benches: merge benchmarks<commit_after>#![feature(test)]

extern crate test;
extern crate itertools;

use test::{black_box};
use itertools::Stride;
use itertools::Itertools;

#[cfg(feature = "unstable")]
use itertools::{ZipTrusted};

use itertools::ZipSlices;

use std::iter::repeat;
use std::cmp;
use std::cmp::Ordering;

#[bench]
fn slice_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter() {
        test::black_box(elt);
    })
}

#[bench]
fn slice_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in xs.iter().rev() {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1) {
        test::black_box(elt);
    })
}

#[bench]
fn stride_iter_rev(b: &mut test::Bencher)
{
    let xs: Vec<_> = repeat(1i32).take(20).collect();
    b.iter(|| for elt in Stride::from_slice(&xs, 1).rev() {
        test::black_box(elt);
    })
}

#[bench]
fn zip_default_zip(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in xs.iter().zip(&ys) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_default_zip3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) {
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
        }
    })
}

/*
#[bench]
fn zip_slices_ziptuple(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];

    b.iter(|| {
        let xs = black_box(&xs);
        let ys = black_box(&ys);
        for (&x, &y) in Zip::new((xs, ys)) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}
*/

#[bench]
fn zip_slices(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in ZipSlices::new(&xs, &ys) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_slices_mut(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let mut ys = black_box(ys);

    b.iter(|| {
        for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[cfg(feature = "unstable")]
#[bench]
fn ziptrusted(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        for (&x, &y) in ZipTrusted::new((xs.iter(), ys.iter())) {
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[cfg(feature = "unstable")]
#[bench]
fn ziptrusted3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        for (&x, &y, &z) in ZipTrusted::new((xs.iter(), ys.iter(), zs.iter())) {
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
        }
    })
}

#[bench]
fn zip_checked_counted_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        // Must slice to equal lengths, and then bounds checks are eliminated!
        let len = cmp::min(xs.len(), ys.len());
        let xs = &xs[..len];
        let ys = &ys[..len];

        for i in 0..len {
            let x = xs[i];
            let y = ys[i];
            test::black_box(x);
            test::black_box(y);
        }
    })
}

#[bench]
fn zip_unchecked_counted_loop(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let xs = black_box(xs);
    let ys = black_box(ys);

    b.iter(|| {
        let len = cmp::min(xs.len(), ys.len());
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            }
        }
    })
}

#[bench]
fn zip_unchecked_counted_loop3(b: &mut test::Bencher)
{
    let xs = vec![0; 1024];
    let ys = vec![0; 768];
    let zs = vec![0; 766];
    let xs = black_box(xs);
    let ys = black_box(ys);
    let zs = black_box(zs);

    b.iter(|| {
        let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
        for i in 0..len {
            unsafe {
            let x = *xs.get_unchecked(i);
            let y = *ys.get_unchecked(i);
            let z = *zs.get_unchecked(i);
            test::black_box(x);
            test::black_box(y);
            test::black_box(z);
            }
        }
    })
}

#[bench]
fn group_by_lazy_1(b: &mut test::Bencher) {
    let mut data = vec![0; 1024];
    for (index, elt) in data.iter_mut().enumerate() {
        *elt = index / 10;
    }

    let data = test::black_box(data);

    b.iter(|| {
        for (_key, group) in &data.iter().group_by_lazy(|elt| **elt) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn group_by_lazy_2(b: &mut test::Bencher) {
    let mut data = vec![0; 1024];
    for (index, elt) in data.iter_mut().enumerate() {
        *elt = index / 2;
    }

    let data = test::black_box(data);

    b.iter(|| {
        for (_key, group) in &data.iter().group_by_lazy(|elt| **elt) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn slice_chunks(b: &mut test::Bencher) {
    let data = vec![0; 1024];

    let data = test::black_box(data);
    let sz = test::black_box(10);

    b.iter(|| {
        for group in data.chunks(sz) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn chunks_lazy_1(b: &mut test::Bencher) {
    let data = vec![0; 1024];

    let data = test::black_box(data);
    let sz = test::black_box(10);

    b.iter(|| {
        for group in &data.iter().chunks_lazy(sz) {
            for elt in group {
                test::black_box(elt);
            }
        }
    })
}

#[bench]
fn equal(b: &mut test::Bencher) {
    let data = vec![7; 1024];
    let l = data.len();
    let alpha = test::black_box(&data[1..]);
    let beta = test::black_box(&data[..l - 1]);
    b.iter(|| {
        itertools::equal(alpha, beta)
    })
}

#[bench]
fn merge_default(b: &mut test::Bencher) {
    let mut data1 = vec![0; 1024];
    let mut data2 = vec![0; 800];
    let mut x = 0;
    for (_, elt) in data1.iter_mut().enumerate() {
        *elt = x;
        x += 1;
    }

    let mut y = 0;
    for (i, elt) in data2.iter_mut().enumerate() {
        *elt += y;
        if i % 3 == 0 {
            y += 3;
        } else {
            y += 0;
        }
    }
    let data1 = test::black_box(data1);
    let data2 = test::black_box(data2);
    b.iter(|| {
        data1.iter().merge(&data2).count()
    })
}

#[bench]
fn merge_by_cmp(b: &mut test::Bencher) {
    let mut data1 = vec![0; 1024];
    let mut data2 = vec![0; 800];
    let mut x = 0;
    for (_, elt) in data1.iter_mut().enumerate() {
        *elt = x;
        x += 1;
    }

    let mut y = 0;
    for (i, elt) in data2.iter_mut().enumerate() {
        *elt += y;
        if i % 3 == 0 {
            y += 3;
        } else {
            y += 0;
        }
    }
    let data1 = test::black_box(data1);
    let data2 = test::black_box(data2);
    b.iter(|| {
        data1.iter().merge_by(&data2, Ord::cmp).count()
    })
}

#[bench]
fn merge_by_lt(b: &mut test::Bencher) {
    let mut data1 = vec![0; 1024];
    let mut data2 = vec![0; 800];
    let mut x = 0;
    for (_, elt) in data1.iter_mut().enumerate() {
        *elt = x;
        x += 1;
    }

    let mut y = 0;
    for (i, elt) in data2.iter_mut().enumerate() {
        *elt += y;
        if i % 3 == 0 {
            y += 3;
        } else {
            y += 0;
        }
    }
    let data1 = test::black_box(data1);
    let data2 = test::black_box(data2);
    b.iter(|| {
        data1.iter().merge_by(&data2, |a, b| if a <= b { Ordering::Less } else { Ordering::Greater }).count()
    })
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Read};

use criterion::*;
use input_buffer::InputBuffer;
use tungstenite::buffer::ReadBuffer;

const CHUNK_SIZE: usize = 4096;

#[inline]
fn current_input_buffer(mut stream: impl Read) {
    let mut buffer = InputBuffer::with_capacity(CHUNK_SIZE);
    while buffer.read_from(&mut stream).unwrap() != 0 {}
}

#[inline]
fn fast_input_buffer(mut stream: impl Read) {
    let mut buffer = ReadBuffer::<CHUNK_SIZE>::new();
    while buffer.read_from(&mut stream).unwrap() != 0 {}
}

fn benchmark(c: &mut Criterion) {
    const STREAM_SIZE: usize = 1024 * 1024 * 4;
    let data: Vec<u8> = (0..STREAM_SIZE).map(|_| rand::random()).collect();
    let stream = Cursor::new(data);

    let mut group = c.benchmark_group("buffers");
    group.throughput(Throughput::Bytes(STREAM_SIZE as u64));
    group.bench_function("InputBuffer", |b| {
        b.iter(|| current_input_buffer(black_box(stream.clone())))
    });
    group.bench_function("ReadBuffer", |b| b.iter(|| fast_input_buffer(black_box(stream.clone()))));
    group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
<commit_msg>Add benchmark for stack read buffer<commit_after>use std::io::{Cursor, Read};
use std::io::Result as IoResult;

use bytes::Buf;
use criterion::*;
use input_buffer::InputBuffer;

use tungstenite::buffer::ReadBuffer;

const CHUNK_SIZE: usize = 4096;

/// A FIFO buffer for reading packets from the network.
#[derive(Debug)]
pub struct StackReadBuffer<const CHUNK_SIZE: usize> {
    storage: Cursor<Vec<u8>>,
    chunk: [u8; CHUNK_SIZE],
}

impl<const CHUNK_SIZE: usize> StackReadBuffer<CHUNK_SIZE> {
    /// Create a new empty input buffer.
    pub fn new() -> Self {
        Self::with_capacity(CHUNK_SIZE)
    }

    /// Create a new empty input buffer with a given `capacity`.
    pub fn with_capacity(capacity: usize) -> Self {
        Self::from_partially_read(Vec::with_capacity(capacity))
    }

    /// Create a input buffer filled with previously read data.
    pub fn from_partially_read(part: Vec<u8>) -> Self {
        Self { storage: Cursor::new(part), chunk: [0; CHUNK_SIZE] }
    }

    /// Get a cursor to the data storage.
    pub fn as_cursor(&self) -> &Cursor<Vec<u8>> {
        &self.storage
    }

    /// Get a cursor to the mutable data storage.
    pub fn as_cursor_mut(&mut self) -> &mut Cursor<Vec<u8>> {
        &mut self.storage
    }

    /// Consume the `ReadBuffer` and get the internal storage.
    pub fn into_vec(mut self) -> Vec<u8> {
        // Current implementation of `tungstenite-rs` expects that the `into_vec()` drains
        // the data from the container that has already been read by the cursor.
        self.clean_up();

        // Now we can safely return the internal container.
        self.storage.into_inner()
    }

    /// Read next portion of data from the given input stream.
    pub fn read_from<S: Read>(&mut self, stream: &mut S) -> IoResult<usize> {
        self.clean_up();
        let size = stream.read(&mut self.chunk)?;
        self.storage.get_mut().extend_from_slice(&self.chunk[..size]);
        Ok(size)
    }

    /// Cleans ups the part of the vector that has been already read by the cursor.
    fn clean_up(&mut self) {
        let pos = self.storage.position() as usize;
        self.storage.get_mut().drain(0..pos).count();
        self.storage.set_position(0);
    }
}

impl<const CHUNK_SIZE: usize> Buf for StackReadBuffer<CHUNK_SIZE> {
    fn remaining(&self) -> usize {
        Buf::remaining(self.as_cursor())
    }

    fn chunk(&self) -> &[u8] {
        Buf::chunk(self.as_cursor())
    }

    fn advance(&mut self, cnt: usize) {
        Buf::advance(self.as_cursor_mut(), cnt)
    }
}

impl<const CHUNK_SIZE: usize> Default for StackReadBuffer<CHUNK_SIZE> {
    fn default() -> Self {
        Self::new()
    }
}

#[inline]
fn input_buffer(mut stream: impl Read) {
    let mut buffer = InputBuffer::with_capacity(CHUNK_SIZE);
    while buffer.read_from(&mut stream).unwrap() != 0 {}
}

#[inline]
fn stack_read_buffer(mut stream: impl Read) {
    let mut buffer = StackReadBuffer::<CHUNK_SIZE>::new();
    while buffer.read_from(&mut stream).unwrap() != 0 {}
}

#[inline]
fn heap_read_buffer(mut stream: impl Read) {
    let mut buffer = ReadBuffer::<CHUNK_SIZE>::new();
    while buffer.read_from(&mut stream).unwrap() != 0 {}
}

fn benchmark(c: &mut Criterion) {
    const STREAM_SIZE: usize = 1024 * 1024 * 4;
    let data: Vec<u8> = (0..STREAM_SIZE).map(|_| rand::random()).collect();
    let stream = Cursor::new(data);

    let mut group = c.benchmark_group("buffers");
    group.throughput(Throughput::Bytes(STREAM_SIZE as u64));
    group.bench_function("InputBuffer", |b| b.iter(|| input_buffer(black_box(stream.clone()))));
    group.bench_function("ReadBuffer (stack)", |b| b.iter(|| stack_read_buffer(black_box(stream.clone()))));
    group.bench_function("ReadBuffer (heap)", |b| b.iter(|| heap_read_buffer(black_box(stream.clone()))));
    group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
<|endoftext|>


<commit_before>#![feature(async_await)]
#![feature(test)]
//#![deny(warnings)]

extern crate test;

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc;
use std::time::Duration;

use futures_util::{stream, StreamExt};
use tokio::runtime::current_thread;
use tokio::sync::oneshot;

use hyper::{Body, Response, Server};
use hyper::service::{make_service_fn, service_fn};

macro_rules! bench_server {
    ($b:ident, $header:expr, $body:expr) => ({
        let _ = pretty_env_logger::try_init();
        let (_until_tx, until_rx) = oneshot::channel::<()>();
        let addr = {
            let (addr_tx, addr_rx) = mpsc::channel();
            std::thread::spawn(move || {
                let addr = "127.0.0.1:0".parse().unwrap();
                let make_svc = make_service_fn(|_| async {
                    Ok::<_, hyper::Error>(service_fn(|_| async {
                        Ok::<_, hyper::Error>(Response::builder()
                            .header($header.0, $header.1)
                            .header("content-type", "text/plain")
                            .body($body())
                            .unwrap()
                        )
                    }))
                });
                let srv = Server::bind(&addr)
                    .serve(make_svc);

                addr_tx.send(srv.local_addr()).unwrap();

                let graceful = srv
                    .with_graceful_shutdown(async {
                        until_rx.await.ok();
                    });
                let mut rt = current_thread::Runtime::new().unwrap();
                rt.spawn(async {
                    if let Err(e) = graceful.await {
                        panic!("server error: {}", e);
                    }
                });
                rt.run().unwrap();
            });

            addr_rx.recv().unwrap()
        };

        let total_bytes = {
            let mut tcp = TcpStream::connect(addr).unwrap();
            tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n").unwrap();
            let mut buf = Vec::new();
            tcp.read_to_end(&mut buf).unwrap()
        };

        let mut tcp = TcpStream::connect(addr).unwrap();
        tcp.set_read_timeout(Some(Duration::from_secs(3))).unwrap();
        let mut buf = [0u8; 8192];

        $b.bytes = 35 + total_bytes as u64;
        $b.iter(|| {
            tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
            let mut sum = 0;
            while sum < total_bytes {
                sum += tcp.read(&mut buf).unwrap();
            }
            assert_eq!(sum, total_bytes);
        });
    })
}

fn body(b: &'static [u8]) -> hyper::Body {
    b.into()
}

#[bench]
fn throughput_fixedsize_small_payload(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "13"), || body(b"Hello, World!"))
}

#[bench]
fn throughput_fixedsize_large_payload(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "1000000"), ||  body(&[b'x'; 1_000_000]))
}

#[bench]
fn throughput_fixedsize_many_chunks(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "1000000"), || {
        static S: &'static [&'static [u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;
        Body::wrap_stream(stream::iter(S.iter()).map(|&s| Ok::<_, String>(s)))
    })
}

#[bench]
fn throughput_chunked_small_payload(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), || body(b"Hello, World!"))
}

#[bench]
fn throughput_chunked_large_payload(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), ||  body(&[b'x'; 1_000_000]))
}

#[bench]
fn throughput_chunked_many_chunks(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), || {
        static S: &'static [&'static [u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;
        Body::wrap_stream(stream::iter(S.iter()).map(|&s| Ok::<_, String>(s)))
    })
}

#[bench]
fn raw_tcp_throughput_small_payload(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();
    std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 8192];
        while rx.try_recv().is_err() {
            sock.read(&mut buf).unwrap();
            sock.write_all(b"\
                HTTP/1.1 200 OK\r\n\
                Content-Length: 13\r\n\
                Content-Type: text/plain; charset=utf-8\r\n\
                Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
                \r\n\
                Hello, World!\
            ").unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 4096];

    b.bytes = 130 + 35;
    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let n = tcp.read(&mut buf).unwrap();
        assert_eq!(n, 130);
    });
    tx.send(()).unwrap();
}

#[bench]
fn raw_tcp_throughput_large_payload(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();

    let srv_head = b"\
        HTTP/1.1 200 OK\r\n\
        Content-Length: 1000000\r\n\
        Content-Type: text/plain; charset=utf-8\r\n\
        Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
        \r\n\
    ";
    std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 8192];
        while rx.try_recv().is_err() {
            let r = sock.read(&mut buf).unwrap();
            if r == 0 {
                break;
            }
            sock.write_all(srv_head).unwrap();
            sock.write_all(&[b'x'; 1_000_000]).unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 8192];

    let expect_read = srv_head.len() + 1_000_000;
    b.bytes = expect_read as u64 + 35;

    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let mut sum = 0;
        while sum < expect_read {
            sum += tcp.read(&mut buf).unwrap();
        }
        assert_eq!(sum, expect_read);
    });
    tx.send(()).unwrap();
}
<commit_msg>test(benches): uncomment deny warning attr<commit_after>#![feature(async_await)]
#![feature(test)]
#![deny(warnings)]

extern crate test;

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc;
use std::time::Duration;

use futures_util::{stream, StreamExt};
use tokio::runtime::current_thread;
use tokio::sync::oneshot;

use hyper::{Body, Response, Server};
use hyper::service::{make_service_fn, service_fn};

macro_rules! bench_server {
    ($b:ident, $header:expr, $body:expr) => ({
        let _ = pretty_env_logger::try_init();
        let (_until_tx, until_rx) = oneshot::channel::<()>();
        let addr = {
            let (addr_tx, addr_rx) = mpsc::channel();
            std::thread::spawn(move || {
                let addr = "127.0.0.1:0".parse().unwrap();
                let make_svc = make_service_fn(|_| async {
                    Ok::<_, hyper::Error>(service_fn(|_| async {
                        Ok::<_, hyper::Error>(Response::builder()
                            .header($header.0, $header.1)
                            .header("content-type", "text/plain")
                            .body($body())
                            .unwrap()
                        )
                    }))
                });
                let srv = Server::bind(&addr)
                    .serve(make_svc);

                addr_tx.send(srv.local_addr()).unwrap();

                let graceful = srv
                    .with_graceful_shutdown(async {
                        until_rx.await.ok();
                    });
                let mut rt = current_thread::Runtime::new().unwrap();
                rt.spawn(async {
                    if let Err(e) = graceful.await {
                        panic!("server error: {}", e);
                    }
                });
                rt.run().unwrap();
            });

            addr_rx.recv().unwrap()
        };

        let total_bytes = {
            let mut tcp = TcpStream::connect(addr).unwrap();
            tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n").unwrap();
            let mut buf = Vec::new();
            tcp.read_to_end(&mut buf).unwrap()
        };

        let mut tcp = TcpStream::connect(addr).unwrap();
        tcp.set_read_timeout(Some(Duration::from_secs(3))).unwrap();
        let mut buf = [0u8; 8192];

        $b.bytes = 35 + total_bytes as u64;
        $b.iter(|| {
            tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
            let mut sum = 0;
            while sum < total_bytes {
                sum += tcp.read(&mut buf).unwrap();
            }
            assert_eq!(sum, total_bytes);
        });
    })
}

fn body(b: &'static [u8]) -> hyper::Body {
    b.into()
}

#[bench]
fn throughput_fixedsize_small_payload(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "13"), || body(b"Hello, World!"))
}

#[bench]
fn throughput_fixedsize_large_payload(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "1000000"), ||  body(&[b'x'; 1_000_000]))
}

#[bench]
fn throughput_fixedsize_many_chunks(b: &mut test::Bencher) {
    bench_server!(b, ("content-length", "1000000"), || {
        static S: &'static [&'static [u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;
        Body::wrap_stream(stream::iter(S.iter()).map(|&s| Ok::<_, String>(s)))
    })
}

#[bench]
fn throughput_chunked_small_payload(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), || body(b"Hello, World!"))
}

#[bench]
fn throughput_chunked_large_payload(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), ||  body(&[b'x'; 1_000_000]))
}

#[bench]
fn throughput_chunked_many_chunks(b: &mut test::Bencher) {
    bench_server!(b, ("transfer-encoding", "chunked"), || {
        static S: &'static [&'static [u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;
        Body::wrap_stream(stream::iter(S.iter()).map(|&s| Ok::<_, String>(s)))
    })
}

#[bench]
fn raw_tcp_throughput_small_payload(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();
    std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 8192];
        while rx.try_recv().is_err() {
            sock.read(&mut buf).unwrap();
            sock.write_all(b"\
                HTTP/1.1 200 OK\r\n\
                Content-Length: 13\r\n\
                Content-Type: text/plain; charset=utf-8\r\n\
                Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
                \r\n\
                Hello, World!\
            ").unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 4096];

    b.bytes = 130 + 35;
    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let n = tcp.read(&mut buf).unwrap();
        assert_eq!(n, 130);
    });
    tx.send(()).unwrap();
}

#[bench]
fn raw_tcp_throughput_large_payload(b: &mut test::Bencher) {
    let (tx, rx) = mpsc::channel();
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();

    let srv_head = b"\
        HTTP/1.1 200 OK\r\n\
        Content-Length: 1000000\r\n\
        Content-Type: text/plain; charset=utf-8\r\n\
        Date: Fri, 12 May 2017 18:21:45 GMT\r\n\
        \r\n\
    ";
    std::thread::spawn(move || {
        let mut sock = listener.accept().unwrap().0;

        let mut buf = [0u8; 8192];
        while rx.try_recv().is_err() {
            let r = sock.read(&mut buf).unwrap();
            if r == 0 {
                break;
            }
            sock.write_all(srv_head).unwrap();
            sock.write_all(&[b'x'; 1_000_000]).unwrap();
        }
    });

    let mut tcp = TcpStream::connect(addr).unwrap();
    let mut buf = [0u8; 8192];

    let expect_read = srv_head.len() + 1_000_000;
    b.bytes = expect_read as u64 + 35;

    b.iter(|| {
        tcp.write_all(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();
        let mut sum = 0;
        while sum < expect_read {
            sum += tcp.read(&mut buf).unwrap();
        }
        assert_eq!(sum, expect_read);
    });
    tx.send(()).unwrap();
}
<|endoftext|>


<commit_before>use std::mem::size_of;
use std::os::wasi::io::RawFd;

#[test]
fn test_raw_fd_layout() {
    /// `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
    /// and `rustc_layout_scalar_valid_range_end`, with values that depend on
    /// the bit width of `RawFd`. If this ever changes, those values will need
    /// to be updated.
    assert_eq!(size_of::<RawFd>(), 4);
}
<commit_msg>Fix syntax for non-doc comments, and use `crate::` instead of `std::`.<commit_after>use crate::mem::size_of;
use crate::os::wasi::io::RawFd;

#[test]
fn test_raw_fd_layout() {
    // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
    // and `rustc_layout_scalar_valid_range_end`, with values that depend on
    // the bit width of `RawFd`. If this ever changes, those values will need
    // to be updated.
    assert_eq!(size_of::<RawFd>(), 4);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2019 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::FractalAnimation;
use fractal_lib::color;
use fractal_lib::escapetime::EscapeTime;
use fractal_lib::geometry;
use num::complex::Complex64;
use std::cmp;
use wasm_bindgen::Clamped;
use web_sys::{CanvasRenderingContext2d, ImageData};

pub struct EscapeTimeAnimation {
    /// The rendering context.
    ctx: CanvasRenderingContext2d,

    /// Which EscapeTime system is being animated. Boxed to encapsulate/avoid generics.
    etsystem: Box<dyn EscapeTime>,

    /// The current part of the fractal we're viewing.
    view_area: [geometry::Point; 2],
}

impl EscapeTimeAnimation {
    pub fn new(
        ctx: CanvasRenderingContext2d,
        etsystem: Box<dyn EscapeTime>,
    ) -> EscapeTimeAnimation {
        let view_area_c = etsystem.default_view_area();
        let view_area = [
            geometry::Point::from(view_area_c[0]),
            geometry::Point::from(view_area_c[1]),
        ];
        EscapeTimeAnimation {
            ctx,
            etsystem,
            view_area,
        }
    }

    fn render(&self) {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();
        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );
        log::debug!("View area: {:?}", self.view_area);
        log::debug!("pixel 0,0 maps to {}", vat.map_pixel_to_point([0.0, 0.0]));
        log::debug!(
            "pixel {},{} maps to {}",
            screen_width as u32,
            screen_height as u32,
            vat.map_pixel_to_point([screen_width.into(), screen_height.into()])
        );

        log::debug!("build color range");
        let colors = color::color_range_linear(
            color::BLACK_U8,
            color::WHITE_U8,
            cmp::min(self.etsystem.max_iterations(), 50) as usize,
        );

        log::debug!("build image pixels");
        let mut image_pixels = (0..screen_height)
            .map(|y| {
                (0..screen_width)
                    .map(|x| {
                        let c: Complex64 =
                            vat.map_pixel_to_point([f64::from(x), f64::from(y)]).into();
                        let (attracted, time) = self.etsystem.test_point(c);
                        if attracted {
                            color::AEBLUE_U8.0.iter()
                        } else {
                            colors[cmp::min(time, 50 - 1) as usize].0.iter()
                        }
                    })
                    .flatten()
                    .collect::<Vec<&u8>>()
            })
            .flatten()
            .cloned()
            .collect::<Vec<u8>>();

        // Construct a Clamped Uint8 Array
        log::debug!("build clamped image array");
        let clamped_image_array = Clamped(image_pixels.as_mut_slice());

        // Create an ImageData from the array
        log::debug!("Create Image Data");
        let image = ImageData::new_with_u8_clamped_array_and_sh(
            clamped_image_array,
            screen_width,
            screen_height,
        )
        .unwrap();

        log::debug!("Put Image Data");
        self.ctx.put_image_data(&image, 0.0, 0.0).unwrap();
    }
}

impl FractalAnimation for EscapeTimeAnimation {
    fn draw_one_frame(&mut self) -> bool {
        self.render();
        false
    }

    fn pixel_to_coordinate(&self, x: f64, y: f64) -> [f64; 2] {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();

        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );
        let pos_point = vat.map_pixel_to_point([x, y]);
        pos_point.into()
    }

    fn zoom(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) -> bool {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();

        // get the vat for the current view area
        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );

        // compute the new view area in the fractal's coordinate system
        let tlp = vat.map_pixel_to_point([x1, y1]);
        let brp = vat.map_pixel_to_point([x2, y2]);

        // update
        self.view_area = [tlp, brp];

        true
    }
}
<commit_msg>Fix warning about unnecessary mut<commit_after>// Copyright (c) 2015-2019 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::FractalAnimation;
use fractal_lib::color;
use fractal_lib::escapetime::EscapeTime;
use fractal_lib::geometry;
use num::complex::Complex64;
use std::cmp;
use wasm_bindgen::Clamped;
use web_sys::{CanvasRenderingContext2d, ImageData};

pub struct EscapeTimeAnimation {
    /// The rendering context.
    ctx: CanvasRenderingContext2d,

    /// Which EscapeTime system is being animated. Boxed to encapsulate/avoid generics.
    etsystem: Box<dyn EscapeTime>,

    /// The current part of the fractal we're viewing.
    view_area: [geometry::Point; 2],
}

impl EscapeTimeAnimation {
    pub fn new(
        ctx: CanvasRenderingContext2d,
        etsystem: Box<dyn EscapeTime>,
    ) -> EscapeTimeAnimation {
        let view_area_c = etsystem.default_view_area();
        let view_area = [
            geometry::Point::from(view_area_c[0]),
            geometry::Point::from(view_area_c[1]),
        ];
        EscapeTimeAnimation {
            ctx,
            etsystem,
            view_area,
        }
    }

    fn render(&self) {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();
        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );
        log::debug!("View area: {:?}", self.view_area);
        log::debug!("pixel 0,0 maps to {}", vat.map_pixel_to_point([0.0, 0.0]));
        log::debug!(
            "pixel {},{} maps to {}",
            screen_width as u32,
            screen_height as u32,
            vat.map_pixel_to_point([screen_width.into(), screen_height.into()])
        );

        log::debug!("build color range");
        let colors = color::color_range_linear(
            color::BLACK_U8,
            color::WHITE_U8,
            cmp::min(self.etsystem.max_iterations(), 50) as usize,
        );

        log::debug!("build image pixels");
        let image_pixels = (0..screen_height)
            .map(|y| {
                (0..screen_width)
                    .map(|x| {
                        let c: Complex64 =
                            vat.map_pixel_to_point([f64::from(x), f64::from(y)]).into();
                        let (attracted, time) = self.etsystem.test_point(c);
                        if attracted {
                            color::AEBLUE_U8.0.iter()
                        } else {
                            colors[cmp::min(time, 50 - 1) as usize].0.iter()
                        }
                    })
                    .flatten()
                    .collect::<Vec<&u8>>()
            })
            .flatten()
            .cloned()
            .collect::<Vec<u8>>();

        // Construct a Clamped Uint8 Array
        log::debug!("build clamped image array");
        let clamped_image_array = Clamped(image_pixels.as_slice());

        // Create an ImageData from the array
        log::debug!("Create Image Data");
        let image = ImageData::new_with_u8_clamped_array_and_sh(
            clamped_image_array,
            screen_width,
            screen_height,
        )
        .unwrap();

        log::debug!("Put Image Data");
        self.ctx.put_image_data(&image, 0.0, 0.0).unwrap();
    }
}

impl FractalAnimation for EscapeTimeAnimation {
    fn draw_one_frame(&mut self) -> bool {
        self.render();
        false
    }

    fn pixel_to_coordinate(&self, x: f64, y: f64) -> [f64; 2] {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();

        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );
        let pos_point = vat.map_pixel_to_point([x, y]);
        pos_point.into()
    }

    fn zoom(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) -> bool {
        let screen_width = self.ctx.canvas().unwrap().width();
        let screen_height = self.ctx.canvas().unwrap().height();

        // get the vat for the current view area
        let vat = geometry::ViewAreaTransformer::new(
            [screen_width.into(), screen_height.into()],
            self.view_area[0],
            self.view_area[1],
        );

        // compute the new view area in the fractal's coordinate system
        let tlp = vat.map_pixel_to_point([x1, y1]);
        let brp = vat.map_pixel_to_point([x2, y2]);

        // update
        self.view_area = [tlp, brp];

        true
    }
}
<|endoftext|>