<commit_before>use std::ffi::{OsString, OsStr};
use std::path::Path;

use ops::{self, ExecEngine, ProcessEngine, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

#[allow(deprecated)] // connect => join in 1.3
pub fn run_tests(manifest_path: &Path,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let mut errors = try!(run_unit_tests(options, test_args, &compilation));

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(try!(run_doc_tests(options, test_args, &compilation)));
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(manifest_path: &Path,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = try!(compile_tests(manifest_path, options));
    let errors = try!(run_unit_tests(options, &args, &compilation));
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(manifest_path: &Path,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = try!(ops::compile(manifest_path,
                                            &options.compile_opts));
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = try!(compilation.target_process(exe, pkg));
        cmd.args(test_args);
        try!(config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        }));
        try!(config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        }));

        if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

#[allow(deprecated)] // connect => join in 1.3
fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            try!(config.shell().status("Doc-tests", name));
            let mut p = try!(compilation.rustdoc_process(package));
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.values() {
                p.arg("-L").arg(native_dep);
            }

            if test_args.len() > 0 {
                p.arg("--test-args").arg(&test_args.connect(" "));
            }

            for cfg in compilation.cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            try!(config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            }));
            if let Err(e) = ExecEngine::exec(&mut ProcessEngine, p) {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<commit_msg>Remove unnecessary mut<commit_after>use std::ffi::{OsString, OsStr};
use std::path::Path;

use ops::{self, ExecEngine, ProcessEngine, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
}

#[allow(deprecated)] // connect => join in 1.3
pub fn run_tests(manifest_path: &Path,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = try!(compile_tests(manifest_path, options));

    if options.no_run {
        return Ok(None)
    }
    let mut errors = try!(run_unit_tests(options, test_args, &compilation));

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(try!(run_doc_tests(options, test_args, &compilation)));
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(manifest_path: &Path,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = try!(compile_tests(manifest_path, options));
    let errors = try!(run_unit_tests(options, &args, &compilation));
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(manifest_path: &Path,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = try!(ops::compile(manifest_path,
                                            &options.compile_opts));
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = try!(compilation.target_process(exe, pkg));
        cmd.args(test_args);
        try!(config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        }));
        try!(config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        }));

        if let Err(e) = ExecEngine::exec(&ProcessEngine, cmd) {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

#[allow(deprecated)] // connect => join in 1.3
fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            try!(config.shell().status("Doc-tests", name));
            let mut p = try!(compilation.rustdoc_process(package));
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.values() {
                p.arg("-L").arg(native_dep);
            }

            if test_args.len() > 0 {
                p.arg("--test-args").arg(&test_args.connect(" "));
            }

            for cfg in compilation.cfgs.iter() {
                p.arg("--cfg").arg(cfg);
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            try!(config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            }));
            if let Err(e) = ExecEngine::exec(&ProcessEngine, p) {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<|endoftext|>


<commit_before>use rustup::dist::Notification as In;
use rustup::utils::tty;
use rustup::utils::Notification as Un;
use rustup::Notification;
use std::collections::VecDeque;
use std::fmt;
use time::precise_time_s;

/// Keep track of this many past download amounts
const DOWNLOAD_TRACK_COUNT: usize = 5;

/// Tracks download progress and displays information about it to a terminal.
pub struct DownloadTracker {
    /// Content-Length of the to-be downloaded object.
    content_len: Option<u64>,
    /// Total data downloaded in bytes.
    total_downloaded: usize,
    /// Data downloaded this second.
    downloaded_this_sec: usize,
    /// Keeps track of amount of data downloaded every last few secs.
    /// Used for averaging the download speed.
    downloaded_last_few_secs: VecDeque<usize>,
    /// Time stamp of the last second
    last_sec: Option<f64>,
    /// How many seconds have elapsed since the download started
    seconds_elapsed: u32,
    /// The terminal we write the information to.
    term: Option<Box<term::StdoutTerminal>>,
    /// Whether we displayed progress for the download or not.
    ///
    /// If the download is quick enough, we don't have time to
    /// display the progress info.
    /// In that case, we do not want to do some cleanup stuff we normally do.
    ///
    /// If we have displayed progress, this is the number of characters we
    /// rendered, so we can erase it cleanly.
    displayed_charcount: Option<usize>,
}

impl DownloadTracker {
    /// Creates a new DownloadTracker.
    pub fn new() -> Self {
        DownloadTracker {
            content_len: None,
            total_downloaded: 0,
            downloaded_this_sec: 0,
            downloaded_last_few_secs: VecDeque::with_capacity(DOWNLOAD_TRACK_COUNT),
            seconds_elapsed: 0,
            last_sec: None,
            term: term::stdout(),
            displayed_charcount: None,
        }
    }

    pub fn handle_notification(&mut self, n: &Notification<'_>) -> bool {
        match *n {
            Notification::Install(In::Utils(Un::DownloadContentLengthReceived(content_len))) => {
                self.content_length_received(content_len);

                true
            }
            Notification::Install(In::Utils(Un::DownloadDataReceived(data))) => {
                if tty::stdout_isatty() && self.term.is_some() {
                    self.data_received(data.len());
                }
                true
            }
            Notification::Install(In::Utils(Un::DownloadFinished)) => {
                self.download_finished();
                true
            }
            _ => false,
        }
    }

    /// Notifies self that Content-Length information has been received.
    pub fn content_length_received(&mut self, content_len: u64) {
        self.content_len = Some(content_len);
    }
    /// Notifies self that data of size `len` has been received.
    pub fn data_received(&mut self, len: usize) {
        self.total_downloaded += len;
        self.downloaded_this_sec += len;

        let current_time = precise_time_s();

        match self.last_sec {
            None => self.last_sec = Some(current_time),
            Some(start) => {
                let elapsed = current_time - start;
                if elapsed >= 1.0 {
                    self.seconds_elapsed += 1;

                    self.display();
                    self.last_sec = Some(current_time);
                    if self.downloaded_last_few_secs.len() == DOWNLOAD_TRACK_COUNT {
                        self.downloaded_last_few_secs.pop_back();
                    }
                    self.downloaded_last_few_secs
                        .push_front(self.downloaded_this_sec);
                    self.downloaded_this_sec = 0;
                }
            }
        }
    }
    /// Notifies self that the download has finished.
    pub fn download_finished(&mut self) {
        if self.displayed_charcount.is_some() {
            // Display the finished state
            self.display();
            let _ = writeln!(self.term.as_mut().unwrap());
        }
        self.prepare_for_new_download();
    }
    /// Resets the state to be ready for a new download.
    fn prepare_for_new_download(&mut self) {
        self.content_len = None;
        self.total_downloaded = 0;
        self.downloaded_this_sec = 0;
        self.downloaded_last_few_secs.clear();
        self.seconds_elapsed = 0;
        self.last_sec = None;
        self.displayed_charcount = None;
    }
    /// Display the tracked download information to the terminal.
    fn display(&mut self) {
        let total_h = HumanReadable(self.total_downloaded as f64);
        let sum = self
            .downloaded_last_few_secs
            .iter()
            .fold(0., |a, &v| a + v as f64);
        let len = self.downloaded_last_few_secs.len();
        let speed = if len > 0 { sum / len as f64 } else { 0. };
        let speed_h = HumanReadable(speed);

        // First, move to the start of the current line and clear it.
        let _ = self.term.as_mut().unwrap().carriage_return();
        // We'd prefer to use delete_line() but on Windows it seems to
        // sometimes do unusual things
        // let _ = self.term.as_mut().unwrap().delete_line();
        // So instead we do:
        if let Some(n) = self.displayed_charcount {
            // This is not ideal as very narrow terminals might mess up,
            // but it is more likely to succeed until term's windows console
            // fixes whatever's up with delete_line().
            let _ = write!(self.term.as_mut().unwrap(), "{}", " ".repeat(n));
            let _ = self.term.as_mut().unwrap().flush();
            let _ = self.term.as_mut().unwrap().carriage_return();
        }

        let output = match self.content_len {
            Some(content_len) => {
                let content_len = content_len as f64;
                let percent = (self.total_downloaded as f64 / content_len) * 100.;
                let content_len_h = HumanReadable(content_len);
                let remaining = content_len - self.total_downloaded as f64;
                let eta_h = HumanReadable(remaining / speed);
                format!(
                    "{} / {} ({:3.0} %) {}/s ETA: {:#}",
                    total_h, content_len_h, percent, speed_h, eta_h
                )
            }
            None => format!("Total: {} Speed: {}/s", total_h, speed_h),
        };

        let _ = write!(self.term.as_mut().unwrap(), "{}", output);
        // Since stdout is typically line-buffered and we don't print a newline, we manually flush.
        let _ = self.term.as_mut().unwrap().flush();
        self.displayed_charcount = Some(output.chars().count());
    }
}

/// Human readable representation of data size in bytes
struct HumanReadable(f64);

impl fmt::Display for HumanReadable {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if f.alternate() {
            // repurposing the alternate mode for ETA
            let sec = self.0;

            if sec.is_infinite() {
                write!(f, "Unknown")
            } else {
                // we're doing modular arithmetic, treat as integer
                let sec = sec as u32;
                if sec > 48 * 3600 {
                    let d = sec / (24 * 3600);
                    let h = sec % (24 * 3600);
                    let min = sec % 3600;
                    let sec = sec % 60;

                    write!(f, "{:3} days {:2} h {:2} min {:2} s", d, h, min, sec) // XYZ days PQ h RS min TU s
                } else if sec > 6_000 {
                    let h = sec / 3600;
                    let min = sec % 3600;
                    let sec = sec % 60;

                    write!(f, "{:3} h {:2} min {:2} s", h, min, sec) // XYZ h PQ min RS s
                } else if sec > 100 {
                    let min = sec / 60;
                    let sec = sec % 60;

                    write!(f, "{:3} min {:2} s", min, sec) // XYZ min PQ s
                } else {
                    write!(f, "{:3.0} s", self.0) // XYZ s
                }
            }
        } else {
            const KIB: f64 = 1024.0;
            const MIB: f64 = KIB * KIB;
            let size = self.0;

            if size >= MIB {
                write!(f, "{:5.1} MiB", size / MIB) // XYZ.P MiB
            } else if size >= KIB {
                write!(f, "{:5.1} KiB", size / KIB)
            } else {
                write!(f, "{:3.0} B", size)
            }
        }
    }
}
<commit_msg>Use term2 from download_tracker<commit_after>use crate::term2;
use rustup::dist::Notification as In;
use rustup::utils::tty;
use rustup::utils::Notification as Un;
use rustup::Notification;
use std::collections::VecDeque;
use std::fmt;
use std::io::Write;
use term::Terminal;
use time::precise_time_s;

/// Keep track of this many past download amounts
const DOWNLOAD_TRACK_COUNT: usize = 5;

/// Tracks download progress and displays information about it to a terminal.
pub struct DownloadTracker {
    /// Content-Length of the to-be downloaded object.
    content_len: Option<u64>,
    /// Total data downloaded in bytes.
    total_downloaded: usize,
    /// Data downloaded this second.
    downloaded_this_sec: usize,
    /// Keeps track of amount of data downloaded every last few secs.
    /// Used for averaging the download speed.
    downloaded_last_few_secs: VecDeque<usize>,
    /// Time stamp of the last second
    last_sec: Option<f64>,
    /// How many seconds have elapsed since the download started
    seconds_elapsed: u32,
    /// The terminal we write the information to.
    /// XXX: Could be a term trait, but with #1818 on the horizon that
    ///      is a pointless change to make - better to let that transition
    ///      happen and take stock after that.
    term: term2::StdoutTerminal,
    /// Whether we displayed progress for the download or not.
    ///
    /// If the download is quick enough, we don't have time to
    /// display the progress info.
    /// In that case, we do not want to do some cleanup stuff we normally do.
    ///
    /// If we have displayed progress, this is the number of characters we
    /// rendered, so we can erase it cleanly.
    displayed_charcount: Option<usize>,
}

impl DownloadTracker {
    /// Creates a new DownloadTracker.
    pub fn new() -> Self {
        DownloadTracker {
            content_len: None,
            total_downloaded: 0,
            downloaded_this_sec: 0,
            downloaded_last_few_secs: VecDeque::with_capacity(DOWNLOAD_TRACK_COUNT),
            seconds_elapsed: 0,
            last_sec: None,
            term: term2::stdout(),
            displayed_charcount: None,
        }
    }

    pub fn handle_notification(&mut self, n: &Notification<'_>) -> bool {
        match *n {
            Notification::Install(In::Utils(Un::DownloadContentLengthReceived(content_len))) => {
                self.content_length_received(content_len);

                true
            }
            Notification::Install(In::Utils(Un::DownloadDataReceived(data))) => {
                if tty::stdout_isatty() {
                    self.data_received(data.len());
                }
                true
            }
            Notification::Install(In::Utils(Un::DownloadFinished)) => {
                self.download_finished();
                true
            }
            _ => false,
        }
    }

    /// Notifies self that Content-Length information has been received.
    pub fn content_length_received(&mut self, content_len: u64) {
        self.content_len = Some(content_len);
    }
    /// Notifies self that data of size `len` has been received.
    pub fn data_received(&mut self, len: usize) {
        self.total_downloaded += len;
        self.downloaded_this_sec += len;

        let current_time = precise_time_s();

        match self.last_sec {
            None => self.last_sec = Some(current_time),
            Some(start) => {
                let elapsed = current_time - start;
                if elapsed >= 1.0 {
                    self.seconds_elapsed += 1;

                    self.display();
                    self.last_sec = Some(current_time);
                    if self.downloaded_last_few_secs.len() == DOWNLOAD_TRACK_COUNT {
                        self.downloaded_last_few_secs.pop_back();
                    }
                    self.downloaded_last_few_secs
                        .push_front(self.downloaded_this_sec);
                    self.downloaded_this_sec = 0;
                }
            }
        }
    }
    /// Notifies self that the download has finished.
    pub fn download_finished(&mut self) {
        if self.displayed_charcount.is_some() {
            // Display the finished state
            self.display();
            let _ = writeln!(self.term);
        }
        self.prepare_for_new_download();
    }
    /// Resets the state to be ready for a new download.
    fn prepare_for_new_download(&mut self) {
        self.content_len = None;
        self.total_downloaded = 0;
        self.downloaded_this_sec = 0;
        self.downloaded_last_few_secs.clear();
        self.seconds_elapsed = 0;
        self.last_sec = None;
        self.displayed_charcount = None;
    }
    /// Display the tracked download information to the terminal.
    fn display(&mut self) {
        let total_h = HumanReadable(self.total_downloaded as f64);
        let sum = self
            .downloaded_last_few_secs
            .iter()
            .fold(0., |a, &v| a + v as f64);
        let len = self.downloaded_last_few_secs.len();
        let speed = if len > 0 { sum / len as f64 } else { 0. };
        let speed_h = HumanReadable(speed);

        // First, move to the start of the current line and clear it.
        let _ = self.term.carriage_return();
        // We'd prefer to use delete_line() but on Windows it seems to
        // sometimes do unusual things
        // let _ = self.term.as_mut().unwrap().delete_line();
        // So instead we do:
        if let Some(n) = self.displayed_charcount {
            // This is not ideal as very narrow terminals might mess up,
            // but it is more likely to succeed until term's windows console
            // fixes whatever's up with delete_line().
            let _ = write!(self.term, "{}", " ".repeat(n));
            let _ = self.term.flush();
            let _ = self.term.carriage_return();
        }

        let output = match self.content_len {
            Some(content_len) => {
                let content_len = content_len as f64;
                let percent = (self.total_downloaded as f64 / content_len) * 100.;
                let content_len_h = HumanReadable(content_len);
                let remaining = content_len - self.total_downloaded as f64;
                let eta_h = HumanReadable(remaining / speed);
                format!(
                    "{} / {} ({:3.0} %) {}/s ETA: {:#}",
                    total_h, content_len_h, percent, speed_h, eta_h
                )
            }
            None => format!("Total: {} Speed: {}/s", total_h, speed_h),
        };

        let _ = write!(self.term, "{}", output);
        // Since stdout is typically line-buffered and we don't print a newline, we manually flush.
        let _ = self.term.flush();
        self.displayed_charcount = Some(output.chars().count());
    }
}

/// Human readable representation of data size in bytes
struct HumanReadable(f64);

impl fmt::Display for HumanReadable {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if f.alternate() {
            // repurposing the alternate mode for ETA
            let sec = self.0;

            if sec.is_infinite() {
                write!(f, "Unknown")
            } else {
                // we're doing modular arithmetic, treat as integer
                let sec = sec as u32;
                if sec > 48 * 3600 {
                    let d = sec / (24 * 3600);
                    let h = sec % (24 * 3600);
                    let min = sec % 3600;
                    let sec = sec % 60;

                    write!(f, "{:3} days {:2} h {:2} min {:2} s", d, h, min, sec) // XYZ days PQ h RS min TU s
                } else if sec > 6_000 {
                    let h = sec / 3600;
                    let min = sec % 3600;
                    let sec = sec % 60;

                    write!(f, "{:3} h {:2} min {:2} s", h, min, sec) // XYZ h PQ min RS s
                } else if sec > 100 {
                    let min = sec / 60;
                    let sec = sec % 60;

                    write!(f, "{:3} min {:2} s", min, sec) // XYZ min PQ s
                } else {
                    write!(f, "{:3.0} s", self.0) // XYZ s
                }
            }
        } else {
            const KIB: f64 = 1024.0;
            const MIB: f64 = KIB * KIB;
            let size = self.0;

            if size >= MIB {
                write!(f, "{:5.1} MiB", size / MIB) // XYZ.P MiB
            } else if size >= KIB {
                write!(f, "{:5.1} KiB", size / KIB)
            } else {
                write!(f, "{:3.0} B", size)
            }
        }
    }
}
<|endoftext|>


<commit_before>use getopts::Options;
use std::env;
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::join;
use tokio::net::{TcpListener, TcpStream};

type BoxedError = Box<dyn std::error::Error + Sync + Send + 'static>;
static DEBUG: AtomicBool = AtomicBool::new(false);

async fn forward(
    bind_ip: &str,
    local_port: i32,
    remote_host: &str,
    remote_port: i32,
) -> Result<(), BoxedError> {
    // Listen on the specified IP and port
    let bind_addr = if bind_ip.contains(':') {
        format!("[{}]:{}", bind_ip, local_port)
    } else {
        format!("{}:{}", bind_ip, local_port)
    };
    let bind_sock = bind_addr
        .parse::<std::net::SocketAddr>()
        .expect("Failed to parse bind address");
    let listener = TcpListener::bind(&bind_sock).await?;
    println!("Listening on {}", listener.local_addr().unwrap());

    // We have either been provided an IP address or a host name.
    // Instead of trying to check its format, just trying creating a SocketAddr from it.
    let parse_result = format!("{}:{}", remote_host, remote_port).parse::<std::net::SocketAddr>();
    let remote_addr = match parse_result {
        Ok(s) => s,
        Err(_) => {
            // It's a hostname; we're going to need to resolve it.
            // Create an async dns resolver

            use trust_dns_resolver::config::*;
            use trust_dns_resolver::TokioAsyncResolver;

            let resolver =
                TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
                    .await
                    .expect("Failed to create DNS resolver");

            let resolutions = resolver
                .lookup_ip(remote_host)
                .await
                .expect("Failed to resolve server IP address!");
            let remote_addr = resolutions
                .iter()
                .nth(1)
                .expect("Failed to resolve server IP address!");
            println!("Resolved {} to {}", remote_host, remote_addr);
            format!("{}:{}", remote_addr, remote_port).parse()?
        }
    };

    loop {
        let (mut client, client_addr) = listener.accept().await?;

        tokio::spawn(async move {
            println!("New connection from {}", client_addr);

            // Establish connection to upstream for each incoming client connection
            let mut remote = TcpStream::connect(&remote_addr).await?;
            let (mut client_recv, mut client_send) = client.split();
            let (mut remote_recv, mut remote_send) = remote.split();

            let (remote_bytes_copied, client_bytes_copied) = join!(
                tokio::io::copy(&mut remote_recv, &mut client_send),
                tokio::io::copy(&mut client_recv, &mut remote_send),
            );

            match remote_bytes_copied {
                Ok(count) => {
                    if DEBUG.load(Ordering::Relaxed) {
                        eprintln!(
                            "Transferred {} bytes from remote client {} to upstream server",
                            count, client_addr
                        );
                    }
                }
                Err(err) => {
                    eprintln!(
                        "Error writing from remote client {} to upstream server!",
                        client_addr
                    );
                    eprintln!("{:?}", err);
                }
            };

            match client_bytes_copied {
                Ok(count) => {
                    if DEBUG.load(Ordering::Relaxed) {
                        eprintln!(
                            "Transferred {} bytes from upstream server to remote client {}",
                            count, client_addr
                        );
                    }
                }
                Err(err) => {
                    eprintln!(
                        "Error writing bytes from upstream server to remote client {}",
                        client_addr
                    );
                    eprintln!("{:?}", err);
                }
            };

            let r: Result<(), BoxedError> = Ok(());
            r
        });
    }
}

pub fn main() {}
<commit_msg>added first getopts<commit_after>use getopts::Options;
use std::env;
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::join;
use tokio::net::{TcpListener, TcpStream};

type BoxedError = Box<dyn std::error::Error + Sync + Send + 'static>;
static DEBUG: AtomicBool = AtomicBool::new(false);

async fn forward(
    bind_ip: &str,
    local_port: i32,
    remote_host: &str,
    remote_port: i32,
) -> Result<(), BoxedError> {
    // Listen on the specified IP and port
    let bind_addr = if bind_ip.contains(':') {
        format!("[{}]:{}", bind_ip, local_port)
    } else {
        format!("{}:{}", bind_ip, local_port)
    };
    let bind_sock = bind_addr
        .parse::<std::net::SocketAddr>()
        .expect("Failed to parse bind address");
    let listener = TcpListener::bind(&bind_sock).await?;
    println!("Listening on {}", listener.local_addr().unwrap());

    // We have either been provided an IP address or a host name.
    // Instead of trying to check its format, just trying creating a SocketAddr from it.
    let parse_result = format!("{}:{}", remote_host, remote_port).parse::<std::net::SocketAddr>();
    let remote_addr = match parse_result {
        Ok(s) => s,
        Err(_) => {
            // It's a hostname; we're going to need to resolve it.
            // Create an async dns resolver

            use trust_dns_resolver::config::*;
            use trust_dns_resolver::TokioAsyncResolver;

            let resolver =
                TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
                    .await
                    .expect("Failed to create DNS resolver");

            let resolutions = resolver
                .lookup_ip(remote_host)
                .await
                .expect("Failed to resolve server IP address!");
            let remote_addr = resolutions
                .iter()
                .nth(1)
                .expect("Failed to resolve server IP address!");
            println!("Resolved {} to {}", remote_host, remote_addr);
            format!("{}:{}", remote_addr, remote_port).parse()?
        }
    };

    loop {
        let (mut client, client_addr) = listener.accept().await?;

        tokio::spawn(async move {
            println!("New connection from {}", client_addr);

            // Establish connection to upstream for each incoming client connection
            let mut remote = TcpStream::connect(&remote_addr).await?;
            let (mut client_recv, mut client_send) = client.split();
            let (mut remote_recv, mut remote_send) = remote.split();

            let (remote_bytes_copied, client_bytes_copied) = join!(
                tokio::io::copy(&mut remote_recv, &mut client_send),
                tokio::io::copy(&mut client_recv, &mut remote_send),
            );

            match remote_bytes_copied {
                Ok(count) => {
                    if DEBUG.load(Ordering::Relaxed) {
                        eprintln!(
                            "Transferred {} bytes from remote client {} to upstream server",
                            count, client_addr
                        );
                    }
                }
                Err(err) => {
                    eprintln!(
                        "Error writing from remote client {} to upstream server!",
                        client_addr
                    );
                    eprintln!("{:?}", err);
                }
            };

            match client_bytes_copied {
                Ok(count) => {
                    if DEBUG.load(Ordering::Relaxed) {
                        eprintln!(
                            "Transferred {} bytes from upstream server to remote client {}",
                            count, client_addr
                        );
                    }
                }
                Err(err) => {
                    eprintln!(
                        "Error writing bytes from upstream server to remote client {}",
                        client_addr
                    );
                    eprintln!("{:?}", err);
                }
            };

            let r: Result<(), BoxedError> = Ok(());
            r
        });
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

pub fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("o", "", "set remote host for the forwarding", "REMOTE_HOST");
    opts.optopt("i", "", "set local port  for the forwarding", "LOCAL_HOST");
    opts.optopt(
        "p",
        "",
        "set remote port  for the forwarding",
        "REMOTE PORT",
    );
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            panic!(f.to_string())
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
}
<|endoftext|>


<commit_before>use std::iter::Iterator;

#[deriving(Clone, PartialEq, Show)]
pub enum SequenceItem {
    Number(uint),
    Range(Box<SequenceItem>, Box<SequenceItem>),
    Wildcard
}

// TODO: Find a way to handle sequences in O(1) as currently, the memory usage
// of the vec returned by this function scales at O(n).
pub fn iterator(sequence_set: Vec<SequenceItem>, max_id: uint) -> Vec<uint> {
    // If the number of possible messages is 0, we return and empty vec.
    if max_id == 0 { return Vec::new() }

    let stop = max_id + 1;

    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            & Number(num) => { items.push(num) },
            & Range(ref a, ref b) => {
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }
                if min > stop { min = stop; }
                if max > stop { max = stop; }
                let seq_range: Vec<uint> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            & Wildcard => {
                // If the sequence set contains the wildcard operator, it spans
                // the entire possible range of messages.
                return range(1, stop).collect()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    let items: Vec<uint> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

#[test]
fn test_sequence_num() {
    assert_eq!(iterator(vec![Number(4324)], 5000), vec![4324]);
    assert_eq!(iterator(vec![Number(23), Number(44)], 5000), vec![23, 44]);
    assert_eq!(iterator(vec![Number(6), Number(6), Number(2)], 5000), vec![2, 6]);
}

#[test]
fn test_sequence_past_end() {
    assert_eq!(iterator(vec![Number(4324)], 100), Vec::new());
    assert_eq!(iterator(vec![Number(23), Number(44)], 30), vec![23]);
    assert_eq!(iterator(vec![Number(6), Number(6), Number(2)], 4), vec![2]);
}

#[test]
fn test_sequence_range() {
    assert_eq!(iterator(vec![Range(box Number(6), box Wildcard)], 10), vec![6, 7, 8, 9, 10]);
    assert_eq!(iterator(vec![Range(box Number(1), box Number(10))], 4), vec![1, 2, 3, 4]);
    assert_eq!(iterator(vec![Range(box Wildcard, box Number(8)), Number(9), Number(2), Number(2)], 12), vec![2, 8, 9, 10, 11, 12]);
}

#[test]
fn test_sequence_wildcard() {
    assert_eq!(iterator(vec![Range(box Number(10), box Wildcard), Wildcard], 6), vec![1, 2, 3, 4, 5, 6]);
    assert_eq!(iterator(vec![Wildcard, Number(8)], 3), vec![1, 2, 3]);
}

#[test]
fn test_sequence_complex() {
    assert_eq!(iterator(
            vec![Number(1), Number(3), Range(box Number(5), box Number(7)), Number(9), Number(12), Range(box Number(15), box Wildcard)], 13),
            vec![1, 3, 5, 6, 7, 9, 12, 13]);
}
<commit_msg>Fix syntax<commit_after>use std::iter::Iterator;

#[deriving(Clone, PartialEq, Show)]
pub enum SequenceItem {
    Number(uint),
    Range(Box<SequenceItem>, Box<SequenceItem>),
    Wildcard
}

// TODO: Find a way to handle sequences in O(1) as currently, the memory usage
// of the vec returned by this function scales at O(n).
pub fn iterator(sequence_set: Vec<SequenceItem>, max_id: uint) -> Vec<uint> {
    // If the number of possible messages is 0, we return and empty vec.
    if max_id == 0 { return Vec::new() }

    let stop = max_id + 1;

    let mut items = Vec::new();
    for item in sequence_set.iter() {
        match item {
            &Number(num) => { items.push(num) },
            &Range(ref a, ref b) => {
                let a = match **a {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let b = match **b {
                    Number(num) => { num },
                    Wildcard => { max_id }
                    Range(_, _) => {
                        error!("A range of ranges is invalid.");
                        continue;
                    }
                };
                let mut min = 0;
                let mut max = 0;
                if a <= b {
                    min = a;
                    max = b;
                } else {
                    min = b;
                    max = a;
                }
                if min > stop { min = stop; }
                if max > stop { max = stop; }
                let seq_range: Vec<uint> = range(min, max + 1).collect();
                items.push_all(seq_range.as_slice());
            },
            &Wildcard => {
                // If the sequence set contains the wildcard operator, it spans
                // the entire possible range of messages.
                return range(1, stop).collect()
            }
        }
    }

    // Sort and remove duplicates.
    items.sort();
    items.dedup();
    // Remove all elements that are greater than the maximum.
    let items: Vec<uint> = items.into_iter().filter(|&x| x <= max_id).collect();
    return items;
}

#[test]
fn test_sequence_num() {
    assert_eq!(iterator(vec![Number(4324)], 5000), vec![4324]);
    assert_eq!(iterator(vec![Number(23), Number(44)], 5000), vec![23, 44]);
    assert_eq!(iterator(vec![Number(6), Number(6), Number(2)], 5000), vec![2, 6]);
}

#[test]
fn test_sequence_past_end() {
    assert_eq!(iterator(vec![Number(4324)], 100), Vec::new());
    assert_eq!(iterator(vec![Number(23), Number(44)], 30), vec![23]);
    assert_eq!(iterator(vec![Number(6), Number(6), Number(2)], 4), vec![2]);
}

#[test]
fn test_sequence_range() {
    assert_eq!(iterator(vec![Range(box Number(6), box Wildcard)], 10), vec![6, 7, 8, 9, 10]);
    assert_eq!(iterator(vec![Range(box Number(1), box Number(10))], 4), vec![1, 2, 3, 4]);
    assert_eq!(iterator(vec![Range(box Wildcard, box Number(8)), Number(9), Number(2), Number(2)], 12), vec![2, 8, 9, 10, 11, 12]);
}

#[test]
fn test_sequence_wildcard() {
    assert_eq!(iterator(vec![Range(box Number(10), box Wildcard), Wildcard], 6), vec![1, 2, 3, 4, 5, 6]);
    assert_eq!(iterator(vec![Wildcard, Number(8)], 3), vec![1, 2, 3]);
}

#[test]
fn test_sequence_complex() {
    assert_eq!(iterator(
            vec![Number(1), Number(3), Range(box Number(5), box Number(7)), Number(9), Number(12), Range(box Number(15), box Wildcard)], 13),
            vec![1, 3, 5, 6, 7, 9, 12, 13]);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq, Clone)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // FIXME(rust#8803): workaround for lack of CTFE function on enum types to return length
    NumBuckets,
}
struct ProfilerBucket {
    category: ProfilerCategory,
    data: ~[float],
}
impl ProfilerBucket {
    fn new(category: ProfilerCategory) -> ProfilerBucket {
        ProfilerBucket {
            category: category,
            data: ~[],
        }
    }
}
// FIXME(rust#5873) this should be initialized by a NumBuckets cast
type ProfilerBuckets = [ProfilerBucket, ..13];

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    fn empty_buckets() -> ProfilerBuckets {
        [
            ProfilerBucket::new(CompositingCategory),
            ProfilerBucket::new(LayoutQueryCategory),
            ProfilerBucket::new(LayoutPerformCategory),
            ProfilerBucket::new(LayoutAuxInitCategory),
            ProfilerBucket::new(LayoutSelectorMatchCategory),
            ProfilerBucket::new(LayoutTreeBuilderCategory),
            ProfilerBucket::new(LayoutMainCategory),
            ProfilerBucket::new(LayoutShapingCategory),
            ProfilerBucket::new(LayoutDispListBuildCategory),
            ProfilerBucket::new(GfxRegenAvailableFontsCategory),
            ProfilerBucket::new(RenderingDrawingCategory),
            ProfilerBucket::new(RenderingPrepBuffCategory),
            ProfilerBucket::new(RenderingCategory),
        ]
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets[category as uint].data.push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for &ProfilerBucket { category: ref category, data: ref mut data } in self.buckets.mut_iter() {
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

#[cfg(test)]
mod test {
    // ensure that the order of the buckets matches the order of the enum categories
    #[test]
    fn check_order() {
        let buckets = ProfilerCategory::empty_buckets();
        for (i, bucket) in buckets.iter().enumerate() {
            assert!(bucket.category as uint == i);
        }
    }
}
<commit_msg>use HashMap instead of vector for profiler buckets<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;
use std::hashmap::HashMap;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

#[deriving(Eq, Clone, IterBytes)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // FIXME(rust#8803): workaround for lack of CTFE function on enum types to return length
    NumBuckets,
}
type ProfilerBuckets = HashMap<ProfilerCategory, ~[float]>;

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    fn empty_buckets() -> ProfilerBuckets {
        let mut buckets = HashMap::with_capacity(NumBuckets as uint);
        buckets.insert(CompositingCategory, ~[]);
        buckets.insert(LayoutQueryCategory, ~[]);
        buckets.insert(LayoutPerformCategory, ~[]);
        buckets.insert(LayoutAuxInitCategory, ~[]);
        buckets.insert(LayoutSelectorMatchCategory, ~[]);
        buckets.insert(LayoutTreeBuilderCategory, ~[]);
        buckets.insert(LayoutMainCategory, ~[]);
        buckets.insert(LayoutShapingCategory, ~[]);
        buckets.insert(LayoutDispListBuildCategory, ~[]);
        buckets.insert(GfxRegenAvailableFontsCategory, ~[]);
        buckets.insert(RenderingDrawingCategory, ~[]);
        buckets.insert(RenderingPrepBuffCategory, ~[]);
        buckets.insert(RenderingCategory, ~[]);

        buckets
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets.get_mut(&category).push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for (category, data) in self.buckets.mut_iter() {
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

#[cfg(test)]
mod test {
    // ensure that the order of the buckets matches the order of the enum categories
    #[test]
    fn check_order() {
        let buckets = ProfilerCategory::empty_buckets();
        assert!(buckets.len() == NumBuckets as uint);
    }
}
<|endoftext|>


<commit_before>//! A `Block` is a linear sequences of `Instruction`.
//!
//! A `Block` must belong to a `ControlFlowGraph`. A `Block` contains many `Instruction`.
//!
//! When building a series of `Operation`/`Instruction`, we normally do so by calling the relevant
//! method directly on the block where we wish to add the `Instruction`.
//!
//! To create a `Block`, call `ControlFlowGraph::new_block`.

use il::*;
use std::fmt;

/// A basic block in Falcon IL.
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Block {
    /// The index of the block.
    index: u64,
    /// an internal counter for the next block-unique instruction.
    next_instruction_index: u64,
    /// An internal counter for the next block-unique temporary variable.
    next_temp_index: u64,
    /// The instructions for this block.
    instructions: Vec<Instruction>,
}

impl Block {
    pub(crate) fn new(index: u64) -> Block {
        Block {
            index: index,
            next_instruction_index: 0,
            next_temp_index: 0,
            instructions: Vec::new()
        }
    }

    fn new_instruction_index(&mut self) -> u64 {
        let instruction_index = self.next_instruction_index;
        self.next_instruction_index = instruction_index + 1;
        instruction_index
    }

    fn push(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }

    /// Get the address of the first instruction in this block
    pub fn address(&self) -> Option<u64> {
        if let Some(ref instruction) = self.instructions.first() {
            instruction.address()
        }
        else {
            None
        }
    }

    /// Appends the contents of another `Block` to this `Block`.
    ///
    /// Instruction indices are updated accordingly.
    pub fn append(&mut self, other: &Block) {
        for instruction in other.instructions().iter() {
            let instruction = instruction.clone_new_index(self.new_instruction_index());
            self.instructions.push(instruction);
        }
    }

    /// Returns the index of this `Block`
    pub fn index(&self) -> u64 {
        self.index
    }

    /// Returns instructions for this `Block`
    pub fn instructions(&self) -> &Vec<Instruction> {
        &self.instructions
    }

    /// Returns a mutable reference to the instructions for this `Block`.
    pub fn instructions_mut(&mut self) -> &mut Vec<Instruction> {
        &mut self.instructions
    }

    /// Returns try if this `Block` is empty, meaning it has no `Instruction`
    pub fn is_empty(&self) -> bool {
        self.instructions.is_empty()
    }

    /// Returns an `Instruction` by index, or `None` if the instruction does not
    /// exist.
    pub fn instruction(&self, index: u64) -> Option<&Instruction> {
        for instruction in &self.instructions {
            if instruction.index() == index {
                return Some(instruction);
            }
        }
        None
    }

    /// Returns a mutable reference to an `Instruction` by index, or `None` if
    /// the `Instruction` does not exist.
    pub fn instruction_mut<>(&mut self, index: u64) -> Option<&mut Instruction> {
        for i in 0..self.instructions.len() {
            if self.instructions[i].index() == index {
                return Some(&mut self.instructions[i]);
            }
        }
        None
    }

    /// Deletes an `Instruction` by its index.
    pub fn remove_instruction(&mut self, index: u64) -> Result<()> {
        let mut vec_index = None;
        for i in 0..self.instructions.len() {
            if self.instructions[i].index() == index {
                vec_index = Some(i);
                break;
            }
        }
        match vec_index {
            Some(index) => {
                self.instructions.remove(index);
                Ok(())
            },
            None => Err(format!("No instruction with index {} found", index).into()),
        }
    }

    /// Clone this block and set a new index.
    pub(crate) fn clone_new_index(&self, index: u64) -> Block {
        let mut clone = self.clone();
        clone.index = index;
        clone
    }

    /// Generates a temporary scalar unique to this block.
    pub fn temp(&mut self, bits: usize) -> Scalar {
        let next_index = self.next_temp_index;
        self.next_temp_index = next_index + 1;
        Scalar::new(format!("temp_{}.{}", self.index, next_index), bits)
    }

    /// Adds an assign operation to the end of this block.
    pub fn assign(&mut self, dst: Scalar, src: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::assign(index, dst, src));
    }

    /// Adds a store operation to the end of this block.
    pub fn store(&mut self, address: Expression, src: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::store(index, address, src))
    }

    /// Adds a load operation to the end of this block.
    pub fn load(&mut self, dst: Scalar, address: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::load(index, dst, address));
    }

    /// Adds a conditional branch operation to the end of this block.
    pub fn branch(&mut self, dst: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::branch(index, dst));
    }

    /// Adds a raise operation to the end of this block.
    pub fn raise(&mut self, expr: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::raise(index, expr));
    }
}

impl graph::Vertex for Block {
    fn index (&self) -> u64 { self.index }
    fn dot_label(&self) -> String { format!("{}", self) }
}

impl fmt::Display for Block {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "[ Block: 0x{:X} ]", self.index));
        for instruction in self.instructions() {
            try!(writeln!(f, "{}", instruction));
        }
        Ok(())
    }
}<commit_msg>Use cleaner code in il::Block<commit_after>//! A `Block` is a linear sequences of `Instruction`.
//!
//! A `Block` must belong to a `ControlFlowGraph`. A `Block` contains many `Instruction`.
//!
//! When building a series of `Operation`/`Instruction`, we normally do so by calling the relevant
//! method directly on the block where we wish to add the `Instruction`.
//!
//! To create a `Block`, call `ControlFlowGraph::new_block`.

use il::*;
use std::fmt;

/// A basic block in Falcon IL.
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Block {
    /// The index of the block.
    index: u64,
    /// an internal counter for the next block-unique instruction.
    next_instruction_index: u64,
    /// An internal counter for the next block-unique temporary variable.
    next_temp_index: u64,
    /// The instructions for this block.
    instructions: Vec<Instruction>,
}

impl Block {
    pub(crate) fn new(index: u64) -> Block {
        Block {
            index: index,
            next_instruction_index: 0,
            next_temp_index: 0,
            instructions: Vec::new()
        }
    }

    fn new_instruction_index(&mut self) -> u64 {
        let instruction_index = self.next_instruction_index;
        self.next_instruction_index = instruction_index + 1;
        instruction_index
    }

    fn push(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }

    /// Get the address of the first instruction in this block
    pub fn address(&self) -> Option<u64> {
        self.instructions
            .first()
            .map(|instruction| instruction.address())
            .unwrap_or(None)
    }

    /// Appends the contents of another `Block` to this `Block`.
    ///
    /// Instruction indices are updated accordingly.
    pub fn append(&mut self, other: &Block) {
        other.instructions().into_iter().for_each(|instruction| {
            let index = self.new_instruction_index();
            self.instructions.push(instruction.clone_new_index(index));
        })
    }

    /// Returns the index of this `Block`
    pub fn index(&self) -> u64 {
        self.index
    }

    /// Returns instructions for this `Block`
    pub fn instructions(&self) -> &Vec<Instruction> {
        &self.instructions
    }

    /// Returns a mutable reference to the instructions for this `Block`.
    pub fn instructions_mut(&mut self) -> &mut Vec<Instruction> {
        &mut self.instructions
    }

    /// Returns try if this `Block` is empty, meaning it has no `Instruction`
    pub fn is_empty(&self) -> bool {
        self.instructions.is_empty()
    }

    /// Returns an `Instruction` by index, or `None` if the instruction does not
    /// exist.
    pub fn instruction(&self, index: u64) -> Option<&Instruction> {
        self.instructions
            .iter()
            .find(|instruction| instruction.index() == index)
    }

    /// Returns a mutable reference to an `Instruction` by index, or `None` if
    /// the `Instruction` does not exist.
    pub fn instruction_mut<>(&mut self, index: u64) -> Option<&mut Instruction> {
        self.instructions
            .iter_mut()
            .find(|instruction| instruction.index() == index)
    }

    /// Deletes an `Instruction` by its index.
    pub fn remove_instruction(&mut self, index: u64) -> Result<()> {
        self.instructions
            .iter()
            .position(|instruction| instruction.index() == index)
            .map(|index| { self.instructions.remove(index); })
            .ok_or(format!("No instruction with index {} found", index).into())
    }

    /// Clone this block and set a new index.
    pub(crate) fn clone_new_index(&self, index: u64) -> Block {
        let mut clone = self.clone();
        clone.index = index;
        clone
    }

    /// Generates a temporary scalar unique to this block.
    pub fn temp(&mut self, bits: usize) -> Scalar {
        let next_index = self.next_temp_index;
        self.next_temp_index = next_index + 1;
        Scalar::new(format!("temp_{}.{}", self.index, next_index), bits)
    }

    /// Adds an assign operation to the end of this block.
    pub fn assign(&mut self, dst: Scalar, src: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::assign(index, dst, src));
    }

    /// Adds a store operation to the end of this block.
    pub fn store(&mut self, address: Expression, src: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::store(index, address, src))
    }

    /// Adds a load operation to the end of this block.
    pub fn load(&mut self, dst: Scalar, address: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::load(index, dst, address));
    }

    /// Adds a conditional branch operation to the end of this block.
    pub fn branch(&mut self, dst: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::branch(index, dst));
    }

    /// Adds a raise operation to the end of this block.
    pub fn raise(&mut self, expr: Expression) {
        let index = self.new_instruction_index();
        self.push(Instruction::raise(index, expr));
    }
}

impl graph::Vertex for Block {
    fn index (&self) -> u64 { self.index }
    fn dot_label(&self) -> String { format!("{}", self) }
}

impl fmt::Display for Block {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "[ Block: 0x{:X} ]", self.index));
        for instruction in self.instructions() {
            try!(writeln!(f, "{}", instruction));
        }
        Ok(())
    }
}<|endoftext|>


<commit_before>use {TypedDecider, ImpliedDeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision,
     Threadsafe, Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

impl Decider for LeakyBucket {}

impl MultiDecider for LeakyBucket {}

impl TypedDecider for LeakyBucket {
    /// The leaky bucket can provide an approximation for how long to
    /// sleep until one token is available again. (This does not
    /// account for multiple requests attempting to use the same
    /// token; schedulers relying on this must account for phenomena
    /// like thundering herds.)
    type T = Duration;
}

#[derive(Debug, Clone)]
/// Implements the industry-standard leaky bucket rate-limiting
/// as-a-meter. The bucket keeps a "fill height", pretending to drip
/// steadily (which reduces the fill height), and increases the fill
/// height with every cell that is found conforming. If cells would
/// make the bucket overflow, they count as non-conforming.
///
/// # Drip implementation
///
/// Instead of having a background task update the bucket's fill
/// level, this implementation re-computes the fill level of the
/// bucket on every call to [`check`](#method.check) and related
/// methods.
///
/// # Wait time calculation
///
/// If the cell does not fit, this implementation computes the minimum
/// wait time until the cell can be accomodated. This minimum wait
/// time does not account for thundering herd effects or other
/// problems in concurrent resource acquisition, so users of this
/// library must take care to apply positive jitter to these wait
/// times.
///
/// # Example
/// ``` rust
/// # use ratelimit_meter::{Decider, LeakyBucket, Decision};
/// let mut lb: LeakyBucket = LeakyBucket::per_second(2).unwrap();
/// assert_eq!(Decision::Yes, lb.check().unwrap());
/// ```
pub struct LeakyBucket {
    last: Option<Instant>,
    full: Duration,
    current: Duration,
    token_interval: Duration,
}

impl LeakyBucket {
    /// Constructs and returns a leaky-bucket rate-limiter allowing as
    /// many cells on average as the given capacity per time duration.
    /// ## Example
    /// ``` rust
    /// # use ratelimit_meter::{Decider, LeakyBucket};
    /// # use std::time::{Duration, Instant};
    /// let now = Instant::now();
    /// let day = Duration::from_secs(86400);
    /// let mut lb = LeakyBucket::new(1, day).unwrap(); // 1 per day
    /// assert!(lb.check_at(now).unwrap().is_compliant());
    ///
    /// assert!(!lb.check_at(now + day/2).unwrap().is_compliant()); // Can't do it half a day later
    /// assert!(lb.check_at(now + day).unwrap().is_compliant()); // Have to wait a day
    /// assert!(lb.check_at(now + day * 2).unwrap().is_compliant()); // ...and then, a day after that.
    /// ```
    pub fn new(capacity: u32, per_duration: Duration) -> Result<LeakyBucket> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        let token_interval = per_duration / capacity;
        Ok(LeakyBucket {
            last: None,
            current: Duration::new(0, 0),
            token_interval: token_interval,
            full: per_duration,
        })
    }

    /// Constructs and returns a leaky-bucket rate-limiter allowing on
    /// average `capacity`/1s cells.
    pub fn per_second(capacity: u32) -> Result<LeakyBucket> {
        LeakyBucket::new(capacity, Duration::from_secs(1))
    }

    /// Wraps the current leaky bucket in a
    /// [`Threadsafe`](../struct.Threadsafe.html).
    pub fn threadsafe(self) -> Threadsafe<LeakyBucket> {
        Threadsafe::new(self)
    }
}

impl MultiDeciderImpl for LeakyBucket {
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Duration>> {
        if self.token_interval * n > self.full {
            return Err(ErrorKind::InsufficientCapacity(n).into());
        }

        let current = self.current;
        let last = match self.last {
            None => {
                self.last = Some(t0);
                t0
            }
            Some(t) => t,
        };
        // Prevent time travel: If any parallel calls get re-ordered,
        // or any tests attempt silly things, make sure to answer from
        // the last query onwards instead.
        let t0 = cmp::max(t0, last);

        self.current = current - cmp::min(t0 - last, current);
        self.last = Some(t0);

        let weight = self.token_interval * n;
        if weight + self.current <= self.full {
            self.current = self.current + weight;
            return Ok(Decision::Yes);
        }
        let wait_period = (weight + current) - self.full;
        return Ok(Decision::No(wait_period));
    }
}

impl ImpliedDeciderImpl for LeakyBucket {}
<commit_msg>Clippy: Remove unnecessary return statement.<commit_after>use {TypedDecider, ImpliedDeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision,
     Threadsafe, Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

impl Decider for LeakyBucket {}

impl MultiDecider for LeakyBucket {}

impl TypedDecider for LeakyBucket {
    /// The leaky bucket can provide an approximation for how long to
    /// sleep until one token is available again. (This does not
    /// account for multiple requests attempting to use the same
    /// token; schedulers relying on this must account for phenomena
    /// like thundering herds.)
    type T = Duration;
}

#[derive(Debug, Clone)]
/// Implements the industry-standard leaky bucket rate-limiting
/// as-a-meter. The bucket keeps a "fill height", pretending to drip
/// steadily (which reduces the fill height), and increases the fill
/// height with every cell that is found conforming. If cells would
/// make the bucket overflow, they count as non-conforming.
///
/// # Drip implementation
///
/// Instead of having a background task update the bucket's fill
/// level, this implementation re-computes the fill level of the
/// bucket on every call to [`check`](#method.check) and related
/// methods.
///
/// # Wait time calculation
///
/// If the cell does not fit, this implementation computes the minimum
/// wait time until the cell can be accomodated. This minimum wait
/// time does not account for thundering herd effects or other
/// problems in concurrent resource acquisition, so users of this
/// library must take care to apply positive jitter to these wait
/// times.
///
/// # Example
/// ``` rust
/// # use ratelimit_meter::{Decider, LeakyBucket, Decision};
/// let mut lb: LeakyBucket = LeakyBucket::per_second(2).unwrap();
/// assert_eq!(Decision::Yes, lb.check().unwrap());
/// ```
pub struct LeakyBucket {
    last: Option<Instant>,
    full: Duration,
    current: Duration,
    token_interval: Duration,
}

impl LeakyBucket {
    /// Constructs and returns a leaky-bucket rate-limiter allowing as
    /// many cells on average as the given capacity per time duration.
    /// ## Example
    /// ``` rust
    /// # use ratelimit_meter::{Decider, LeakyBucket};
    /// # use std::time::{Duration, Instant};
    /// let now = Instant::now();
    /// let day = Duration::from_secs(86400);
    /// let mut lb = LeakyBucket::new(1, day).unwrap(); // 1 per day
    /// assert!(lb.check_at(now).unwrap().is_compliant());
    ///
    /// assert!(!lb.check_at(now + day/2).unwrap().is_compliant()); // Can't do it half a day later
    /// assert!(lb.check_at(now + day).unwrap().is_compliant()); // Have to wait a day
    /// assert!(lb.check_at(now + day * 2).unwrap().is_compliant()); // ...and then, a day after that.
    /// ```
    pub fn new(capacity: u32, per_duration: Duration) -> Result<LeakyBucket> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        let token_interval = per_duration / capacity;
        Ok(LeakyBucket {
            last: None,
            current: Duration::new(0, 0),
            token_interval: token_interval,
            full: per_duration,
        })
    }

    /// Constructs and returns a leaky-bucket rate-limiter allowing on
    /// average `capacity`/1s cells.
    pub fn per_second(capacity: u32) -> Result<LeakyBucket> {
        LeakyBucket::new(capacity, Duration::from_secs(1))
    }

    /// Wraps the current leaky bucket in a
    /// [`Threadsafe`](../struct.Threadsafe.html).
    pub fn threadsafe(self) -> Threadsafe<LeakyBucket> {
        Threadsafe::new(self)
    }
}

impl MultiDeciderImpl for LeakyBucket {
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Duration>> {
        if self.token_interval * n > self.full {
            return Err(ErrorKind::InsufficientCapacity(n).into());
        }

        let current = self.current;
        let last = match self.last {
            None => {
                self.last = Some(t0);
                t0
            }
            Some(t) => t,
        };
        // Prevent time travel: If any parallel calls get re-ordered,
        // or any tests attempt silly things, make sure to answer from
        // the last query onwards instead.
        let t0 = cmp::max(t0, last);

        self.current = current - cmp::min(t0 - last, current);
        self.last = Some(t0);

        let weight = self.token_interval * n;
        if weight + self.current <= self.full {
            self.current = self.current + weight;
            Ok(Decision::Yes)
        } else {
            let wait_period = (weight + current) - self.full;
            Ok(Decision::No(wait_period))
        }
    }
}

impl ImpliedDeciderImpl for LeakyBucket {}
<|endoftext|>


<commit_before>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};

use filters::context::IRect;

use super::Pixel;

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the `ImageSurface` is not unique, that is, its reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
        })
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<commit_msg>Add SharedImageSurface::scale{,_to}()<commit_after>//! Shared access to Cairo image surfaces.
use std::ptr::NonNull;

use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use glib::translate::{Stash, ToGlibPtr};

use filters::context::IRect;

use super::Pixel;

/// Wrapper for a Cairo image surface that allows shared access.
///
/// There doesn't seem to be any good way of making safe shared access to `ImageSurface` pixel
/// data, since a read-only borrowed reference can still be cloned and then modified (for example,
/// via a `Context`). We can't simply use `ImageSurface::get_data()` because in the filter code we
/// have surfaces referenced from multiple places and it would probably add more complexity to
/// remove that and start passing around references.
///
/// This wrapper asserts the uniqueness of its image surface and doesn't permit modifying it.
///
/// Note: originally I had an idea of using `Rc<RefCell<ImageSurface>>` here which allows to create
/// both read-only and unique read-write accessors safely, however then I realized a read-write
/// accessor isn't of much use if it can't expose a Cairo context interface. Cairo contexts have
/// the very same issue that they can be cloned from a read-only reference and break all safety
/// constraints in this way. Thus the only safe way of exposing a Cairo context seemed to be to
/// manually add all Cairo context methods on the accessor forwarding to the underlying Cairo
/// context (without exposing the context itself to prevent cloning), which would result in too
/// much code. Unless it's absolutely required, I'd like to avoid that.
///
/// Having just read-only access simplifies things further dropping the need for `Rc<RefCell<>>`
/// altogether.
#[derive(Debug, Clone)]
pub struct SharedImageSurface {
    surface: ImageSurface,

    data_ptr: NonNull<u8>, // *const.
    width: i32,
    height: i32,
    stride: isize,
}

impl SharedImageSurface {
    /// Creates a `SharedImageSurface` from a unique `ImageSurface`.
    ///
    /// # Panics
    /// Panics if the `ImageSurface` is not unique, that is, its reference count isn't 1.
    #[inline]
    pub fn new(surface: ImageSurface) -> Result<Self, cairo::Status> {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        surface.flush();
        if surface.status() != cairo::Status::Success {
            return Err(surface.status());
        }

        let data_ptr = NonNull::new(unsafe {
            cairo_sys::cairo_image_surface_get_data(surface.to_raw_none())
        }).unwrap();

        let width = surface.get_width();
        let height = surface.get_height();
        let stride = surface.get_stride() as isize;

        Ok(Self {
            surface,
            data_ptr,
            width,
            height,
            stride,
        })
    }

    /// Converts this `SharedImageSurface` back into a Cairo image surface.
    ///
    /// # Panics
    /// Panics if the underlying Cairo image surface is not unique, that is, there are other
    /// instances of `SharedImageSurface` pointing at the same Cairo image surface.
    #[inline]
    pub fn into_image_surface(self) -> ImageSurface {
        let reference_count =
            unsafe { cairo_sys::cairo_surface_get_reference_count(self.surface.to_raw_none()) };
        assert_eq!(reference_count, 1);

        self.surface
    }

    /// Returns the surface width.
    #[inline]
    pub fn width(&self) -> i32 {
        self.width
    }

    /// Returns the surface height.
    #[inline]
    pub fn height(&self) -> i32 {
        self.height
    }

    /// Retrieves the pixel value at the given coordinates.
    #[inline]
    pub fn get_pixel(&self, x: u32, y: u32) -> Pixel {
        assert!(x < self.width as u32);
        assert!(y < self.height as u32);

        let value = unsafe {
            *(self
                .data_ptr
                .as_ptr()
                .offset(y as isize * self.stride + x as isize * 4) as *const u32)
        };

        Pixel {
            r: ((value >> 16) & 0xFF) as u8,
            g: ((value >> 8) & 0xFF) as u8,
            b: (value & 0xFF) as u8,
            a: ((value >> 24) & 0xFF) as u8,
        }
    }

    /// Calls `set_source_surface()` on the given Cairo context.
    #[inline]
    pub fn set_as_source_surface(&self, cr: &cairo::Context, x: f64, y: f64) {
        cr.set_source_surface(&self.surface, x, y);
    }

    /// Returns a new `ImageSurface` with the same contents as the one stored in this
    /// `SharedImageSurface` within the given bounds.
    pub fn copy_surface(&self, bounds: IRect) -> Result<ImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, self.width, self.height)?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            bounds.x0 as f64,
            bounds.y0 as f64,
            (bounds.x1 - bounds.x0) as f64,
            (bounds.y1 - bounds.y0) as f64,
        );
        cr.clip();

        cr.set_source_surface(&self.surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Scales the given surface by `x` and `y` into a surface `width`×`height` in size, clipped by
    /// `bounds`.
    pub fn scale_to(
        &self,
        width: i32,
        height: i32,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;

        {
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                bounds.x0 as f64,
                bounds.y0 as f64,
                (bounds.x1 - bounds.x0) as f64,
                (bounds.y1 - bounds.y0) as f64,
            );
            cr.clip();

            cr.scale(x, y);
            self.set_as_source_surface(&cr, 0.0, 0.0);
            cr.paint();
        }

        Ok(SharedImageSurface::new(output_surface)?)
    }

    /// Returns a scaled version of a surface and bounds.
    #[inline]
    pub fn scale(
        &self,
        bounds: IRect,
        x: f64,
        y: f64,
    ) -> Result<(SharedImageSurface, IRect), cairo::Status> {
        let new_width = (f64::from(self.width) * x).ceil() as i32;
        let new_height = (f64::from(self.height) * x).ceil() as i32;
        let new_bounds = bounds.scale(x, y);

        Ok((
            self.scale_to(new_width, new_height, new_bounds, x, y)?,
            new_bounds,
        ))
    }

    /// Returns a raw pointer to the underlying surface.
    ///
    /// # Safety
    /// The returned pointer must not be used to modify the surface.
    #[inline]
    pub unsafe fn to_glib_none(&self) -> Stash<*mut cairo_sys::cairo_surface_t, ImageSurface> {
        self.surface.to_glib_none()
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate bodyparser;

use std::io::net::ip::Ipv4Addr;

use iron::{Iron, Request, Response, IronResult, Plugin, status};
use bodyparser::BodyParser;

fn log_json(req: &mut Request) -> IronResult<Response> {
    req.get::<BodyParser>().map(|parsed| println!("Parsed Json:\n{}", parsed));
    Ok(Response::with(status::Ok, ""))
}

// With fn main, you now have a running server at port 3000!
// `curl -i "127.0.0.1:3000/" -H "application/json" -d '{"A":"1","B":"2"}'`
// and check out the printed json in your terminal.
fn main() {
    Iron::new(log_json).listen(Ipv4Addr(127, 0, 0, 1), 4000);
}
<commit_msg>Update bodyparser.rs<commit_after>extern crate iron;
extern crate bodyparser;

use std::io::net::ip::Ipv4Addr;

use iron::{Iron, Request, Response, IronResult, Plugin, status};
use bodyparser::BodyParser;

fn log_json(req: &mut Request) -> IronResult<Response> {
    req.get::<BodyParser>().map(|parsed| println!("Parsed Json:\n{}", parsed));
    Ok(Response::with(status::Ok, ""))
}

// With fn main, you now have a running server at port 3000!
// `curl -i "127.0.0.1:3000/" -H "application/json" -d '{"A":"1","B":"2"}'`
// and check out the printed json in your terminal.
fn main() {
    Iron::new(log_json).listen(Ipv4Addr(127, 0, 0, 1), 3000);
}
<|endoftext|>