<commit_before>use clap::{App, Arg, AppSettings, SubCommand, ArgMatches};
use common;
use rustup::{Cfg, Toolchain, command};
use rustup::telemetry::TelemetryMode;
use errors::*;
use rustup_dist::manifest::Component;
use rustup_dist::dist::TargetTriple;
use rustup_utils::utils;
use self_update;
use std::path::Path;

pub fn main() -> Result<()> {
    try!(::self_update::cleanup_self_updater());

    let ref matches = cli().get_matches();
    let verbose = matches.is_present("verbose");
    let ref cfg = try!(common::set_globals(verbose));

    if try!(maybe_upgrade_data(cfg, matches)) {
        return Ok(())
    }

    try!(cfg.check_metadata_version());

    match matches.subcommand() {
        ("default", Some(m)) => try!(default_(cfg, m)),
        ("update", Some(m)) => try!(update(cfg, m)),
        ("run", Some(m)) => try!(run(cfg, m)),
        ("which", Some(m)) => try!(which(cfg, m)),
        ("show", Some(_)) => try!(show(cfg)),
        ("target", Some(c)) => {
            match c.subcommand() {
                ("list", Some(m)) => try!(target_list(cfg, m)),
                ("add", Some(m)) => try!(target_add(cfg, m)),
                ("remove", Some(m)) => try!(target_remove(cfg, m)),
                (_, _) => unreachable!(),
            }
        }
        ("toolchain", Some(c)) => {
            match c.subcommand() {
                ("list", Some(_)) => try!(common::list_toolchains(cfg)),
                ("link", Some(m)) => try!(toolchain_link(cfg, m)),
                ("remove", Some(m)) => try!(toolchain_remove(cfg, m)),
                (_, _) => unreachable!(),
            }
        }
        ("override", Some(c)) => {
            match c.subcommand() {
                ("list", Some(_)) => try!(common::list_overrides(cfg)),
                ("add", Some(m)) => try!(override_add(cfg, m)),
                ("remove", Some(_)) => try!(override_remove(cfg)),
                (_ ,_) => unreachable!(),
            }
        }
        ("doc", Some(m)) => try!(doc(cfg, m)),
        ("self", Some(c)) => {
            match c.subcommand() {
                ("update", Some(_)) => try!(self_update::update()),
                ("uninstall", Some(m)) => try!(self_uninstall(m)),
                (_ ,_) => unreachable!(),
            }
        }
        ("telemetry", Some(c)) => {
            match c.subcommand() {
                ("enable", Some(_)) => try!(set_telemetry(&cfg, TelemetryMode::On)),
                ("disable", Some(_)) => try!(set_telemetry(&cfg, TelemetryMode::Off)),
                ("analyze", Some(_)) => try!(analyze_telemetry(&cfg)),
                (_, _) => unreachable!(),
            }
        }
        (_, _) => unreachable!(),
    }

    Ok(())
}

pub fn cli() -> App<'static, 'static> {
    App::new("rustup")
        .version(common::version())
        .about("The Rust toolchain installer")
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("verbose")
            .help("Enable verbose output")
            .short("v")
            .long("verbose"))
        .subcommand(SubCommand::with_name("default")
            .about("Set the default toolchain")
            .arg(Arg::with_name("toolchain")
                .required(true)))
        .subcommand(SubCommand::with_name("update")
            .about("Update all toolchains, install or update a given toolchain")
            .arg(Arg::with_name("toolchain")
                .required(false))
            .arg(Arg::with_name("no-self-update")
                .help("Don't perform self update when running the `rustup` command")
                .long("no-self-update")
                .takes_value(false)
                .hidden(true)))
        .subcommand(SubCommand::with_name("run")
            .about("Run a command with an environment configured for a given toolchain")
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("toolchain")
                .required(true))
            .arg(Arg::with_name("command")
                .required(true).multiple(true)))
        .subcommand(SubCommand::with_name("which")
            .about("Display which binary will be run for a given command")
            .arg(Arg::with_name("command")
                .required(true)))
        .subcommand(SubCommand::with_name("show")
            .about("Show the active toolchain"))
        .subcommand(SubCommand::with_name("target")
            .about("Modify a toolchain's supported targets")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List installed and available targets")
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true)))
            .subcommand(SubCommand::with_name("add")
                .about("Add a target to a Rust toolchain")
                .arg(Arg::with_name("target")
                    .required(true))
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Remove a target  from a Rust toolchain")
                .arg(Arg::with_name("target")
                    .required(true))
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true))))
        .subcommand(SubCommand::with_name("toolchain")
            .about("Modify or query the installed toolchains")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List installed toolchains"))
            .subcommand(SubCommand::with_name("link")
                .about("Create a custom toolchain by symlinking to a directory")
                .arg(Arg::with_name("toolchain")
                    .required(true))
                .arg(Arg::with_name("path")
                    .required(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Uninstall a toolchain")
                .arg(Arg::with_name("toolchain")
                     .required(true))))
        .subcommand(SubCommand::with_name("override")
            .about("Modify directory toolchain overrides")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List directory toolchain overrides"))
            .subcommand(SubCommand::with_name("add")
                .about("Set the override toolchain for a directory")
                .arg(Arg::with_name("toolchain")
                     .required(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Remove the override toolchain for a directory")))
        .subcommand(SubCommand::with_name("self")
            .about("Modify the rustup installation")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("update")
                .about("Download and install updates to rustup"))
            .subcommand(SubCommand::with_name("uninstall")
                .about("Uninstall rustup.")
                .arg(Arg::with_name("no-prompt")
                     .short("y")))
            .subcommand(SubCommand::with_name("upgrade-data")
                .about("Upgrade the internal data format.")))
        .subcommand(SubCommand::with_name("telemetry")
            .about("rustup telemetry commands")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("enable")
                            .about("Enable rustup telemetry"))
            .subcommand(SubCommand::with_name("disable")
                            .about("Disable rustup telemetry"))
            .subcommand(SubCommand::with_name("analyze")
                            .about("Analyze stored telemetry")))
}

fn maybe_upgrade_data(cfg: &Cfg, m: &ArgMatches) -> Result<bool> {
    match m.subcommand() {
        ("self", Some(c)) => {
            match c.subcommand() {
                ("upgrade-data", Some(_)) => {
                    try!(cfg.upgrade_data());
                    Ok(true)
                }
                _ => Ok(false),
            }
        }
        _ => Ok(false)
    }
}

fn default_(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let ref toolchain = try!(cfg.get_toolchain(toolchain, false));

    let status = if !toolchain.is_custom() {
        Some(try!(toolchain.install_from_dist_if_not_installed()))
    } else if !toolchain.exists() {
        return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
    } else {
        None
    };

    try!(toolchain.make_default());

    if let Some(status) = status {
        println!("");
        try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
    }

    Ok(())
}

fn update(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    if let Some(name) = m.value_of("toolchain") {
        let toolchain = try!(cfg.get_toolchain(name, false));

        let status = if !toolchain.is_custom() {
            Some(try!(toolchain.install_from_dist()))
        } else if !toolchain.exists() {
            return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
        } else {
            None
        };

        if let Some(status) = status {
            println!("");
            try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
        }
    } else {
        try!(common::update_all_channels(cfg, !m.is_present("no-self-update")));
    }

    Ok(())
}

fn run(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let args = m.values_of("command").unwrap();
    let args: Vec<_> = args.collect();
    let cmd = try!(cfg.create_command_for_toolchain(toolchain, args[0]));

    Ok(try!(command::run_command_for_dir(cmd, &args, &cfg)))
}

fn which(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let binary = m.value_of("command").expect("");

    let binary_path = try!(cfg.which_binary(&try!(utils::current_dir()), binary))
                          .expect("binary not found");

    try!(utils::assert_is_file(&binary_path));

    println!("{}", binary_path.display());

    Ok(())
}

fn show(cfg: &Cfg) -> Result<()> {
    let ref cwd = try!(utils::current_dir());
    let override_ = try!(cfg.find_override(cwd));
    if let Some((toolchain, reason)) = override_ {
        println!("{} ({})", toolchain.name(), reason);
        return Ok(());
    }

    let toolchain = try!(cfg.find_default());
    if let Some(toolchain) = toolchain {
        println!("{} (default toolchain)", toolchain.name());
        return Ok(());
    }

    println!("no active toolchain");

    Ok(())
}

fn target_list(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));

    common::list_targets(&toolchain)
}

fn target_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));
    let target = m.value_of("target").expect("");
    let new_component = Component {
        pkg: "rust-std".to_string(),
        target: TargetTriple::from_str(target),
    };

    Ok(try!(toolchain.add_component(new_component)))
}

fn target_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));
    let target = m.value_of("target").expect("");
    let new_component = Component {
        pkg: "rust-std".to_string(),
        target: TargetTriple::from_str(target),
    };

    Ok(try!(toolchain.remove_component(new_component)))
}

fn explicit_or_dir_toolchain<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolchain<'a>> {
    let toolchain = m.value_of("toolchain");
    if let Some(toolchain) = toolchain {
        let toolchain = try!(cfg.get_toolchain(toolchain, false));
        return Ok(toolchain);
    }

    let ref cwd = try!(utils::current_dir());
    let (toolchain, _) = try!(cfg.toolchain_for_dir(cwd));

    Ok(toolchain)
}

fn toolchain_link(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let ref path = m.value_of("path").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, true));

    Ok(try!(toolchain.install_from_dir(Path::new(path), true)))
}

fn toolchain_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, false));

    Ok(try!(toolchain.remove()))
}

fn override_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, false));

    let status = if !toolchain.is_custom() {
        Some(try!(toolchain.install_from_dist_if_not_installed()))
    } else if !toolchain.exists() {
        return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
    } else {
        None
    };

    try!(toolchain.make_override(&try!(utils::current_dir())));

    if let Some(status) = status {
        println!("");
        try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
    }

    Ok(())
}

fn override_remove(cfg: &Cfg) -> Result<()> {
    let ref path = try!(utils::current_dir());

    let ref override_db = cfg.override_db;
    let notify_handler = cfg.notify_handler.as_ref();

    if try!(override_db.find(path, notify_handler)).is_none() {
        info!("no override toolchain for '{}'", path.display());
        return Ok(());
    }

    try!(override_db.remove(path, &cfg.temp_cfg, notify_handler));
    info!("override toolchain for '{}' removed", path.display());
    Ok(())
}

fn doc(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let doc_url = if m.is_present("book") {
        "book/index.html"
    } else if m.is_present("std") {
        "std/index.html"
    } else {
        "index.html"
    };

    Ok(try!(cfg.open_docs_for_dir(&try!(utils::current_dir()), doc_url)))
}

fn self_uninstall(m: &ArgMatches) -> Result<()> {
    let no_prompt = m.is_present("no-prompt");

    self_update::uninstall(no_prompt)
}

fn set_telemetry(cfg: &Cfg, t: TelemetryMode) -> Result<()> {
    match t {
        TelemetryMode::On => Ok(try!(cfg.set_telemetry(true))),
        TelemetryMode::Off => Ok(try!(cfg.set_telemetry(false))),
    }
}

fn analyze_telemetry(cfg: &Cfg) -> Result<()> {
    let analysis = try!(cfg.analyze_telemetry());
    common::show_telemetry(analysis)
}
<commit_msg>Add `rustup doc`.<commit_after>use clap::{App, Arg, ArgGroup, AppSettings, SubCommand, ArgMatches};
use common;
use rustup::{Cfg, Toolchain, command};
use rustup::telemetry::TelemetryMode;
use errors::*;
use rustup_dist::manifest::Component;
use rustup_dist::dist::TargetTriple;
use rustup_utils::utils;
use self_update;
use std::path::Path;

pub fn main() -> Result<()> {
    try!(::self_update::cleanup_self_updater());

    let ref matches = cli().get_matches();
    let verbose = matches.is_present("verbose");
    let ref cfg = try!(common::set_globals(verbose));

    if try!(maybe_upgrade_data(cfg, matches)) {
        return Ok(())
    }

    try!(cfg.check_metadata_version());

    match matches.subcommand() {
        ("default", Some(m)) => try!(default_(cfg, m)),
        ("update", Some(m)) => try!(update(cfg, m)),
        ("run", Some(m)) => try!(run(cfg, m)),
        ("which", Some(m)) => try!(which(cfg, m)),
        ("show", Some(_)) => try!(show(cfg)),
        ("target", Some(c)) => {
            match c.subcommand() {
                ("list", Some(m)) => try!(target_list(cfg, m)),
                ("add", Some(m)) => try!(target_add(cfg, m)),
                ("remove", Some(m)) => try!(target_remove(cfg, m)),
                (_, _) => unreachable!(),
            }
        }
        ("toolchain", Some(c)) => {
            match c.subcommand() {
                ("list", Some(_)) => try!(common::list_toolchains(cfg)),
                ("link", Some(m)) => try!(toolchain_link(cfg, m)),
                ("remove", Some(m)) => try!(toolchain_remove(cfg, m)),
                (_, _) => unreachable!(),
            }
        }
        ("override", Some(c)) => {
            match c.subcommand() {
                ("list", Some(_)) => try!(common::list_overrides(cfg)),
                ("add", Some(m)) => try!(override_add(cfg, m)),
                ("remove", Some(_)) => try!(override_remove(cfg)),
                (_ ,_) => unreachable!(),
            }
        }
        ("doc", Some(m)) => try!(doc(cfg, m)),
        ("self", Some(c)) => {
            match c.subcommand() {
                ("update", Some(_)) => try!(self_update::update()),
                ("uninstall", Some(m)) => try!(self_uninstall(m)),
                (_ ,_) => unreachable!(),
            }
        }
        ("telemetry", Some(c)) => {
            match c.subcommand() {
                ("enable", Some(_)) => try!(set_telemetry(&cfg, TelemetryMode::On)),
                ("disable", Some(_)) => try!(set_telemetry(&cfg, TelemetryMode::Off)),
                ("analyze", Some(_)) => try!(analyze_telemetry(&cfg)),
                (_, _) => unreachable!(),
            }
        }
        (_, _) => unreachable!(),
    }

    Ok(())
}

pub fn cli() -> App<'static, 'static> {
    App::new("rustup")
        .version(common::version())
        .about("The Rust toolchain installer")
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("verbose")
            .help("Enable verbose output")
            .short("v")
            .long("verbose"))
        .subcommand(SubCommand::with_name("default")
            .about("Set the default toolchain")
            .arg(Arg::with_name("toolchain")
                .required(true)))
        .subcommand(SubCommand::with_name("update")
            .about("Update all toolchains, install or update a given toolchain")
            .arg(Arg::with_name("toolchain")
                .required(false))
            .arg(Arg::with_name("no-self-update")
                .help("Don't perform self update when running the `rustup` command")
                .long("no-self-update")
                .takes_value(false)
                .hidden(true)))
        .subcommand(SubCommand::with_name("run")
            .about("Run a command with an environment configured for a given toolchain")
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("toolchain")
                .required(true))
            .arg(Arg::with_name("command")
                .required(true).multiple(true)))
        .subcommand(SubCommand::with_name("which")
            .about("Display which binary will be run for a given command")
            .arg(Arg::with_name("command")
                .required(true)))
        .subcommand(SubCommand::with_name("show")
            .about("Show the active toolchain"))
        .subcommand(SubCommand::with_name("target")
            .about("Modify a toolchain's supported targets")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List installed and available targets")
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true)))
            .subcommand(SubCommand::with_name("add")
                .about("Add a target to a Rust toolchain")
                .arg(Arg::with_name("target")
                    .required(true))
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Remove a target  from a Rust toolchain")
                .arg(Arg::with_name("target")
                    .required(true))
                .arg(Arg::with_name("toolchain")
                    .long("toolchain")
                    .takes_value(true))))
        .subcommand(SubCommand::with_name("toolchain")
            .about("Modify or query the installed toolchains")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List installed toolchains"))
            .subcommand(SubCommand::with_name("link")
                .about("Create a custom toolchain by symlinking to a directory")
                .arg(Arg::with_name("toolchain")
                    .required(true))
                .arg(Arg::with_name("path")
                    .required(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Uninstall a toolchain")
                .arg(Arg::with_name("toolchain")
                     .required(true))))
        .subcommand(SubCommand::with_name("override")
            .about("Modify directory toolchain overrides")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("list")
                .about("List directory toolchain overrides"))
            .subcommand(SubCommand::with_name("add")
                .about("Set the override toolchain for a directory")
                .arg(Arg::with_name("toolchain")
                     .required(true)))
            .subcommand(SubCommand::with_name("remove")
                .about("Remove the override toolchain for a directory")))
        .subcommand(SubCommand::with_name("doc")
            .about("Open the documentation for the current toolchain.")
            .arg(Arg::with_name("book")
                 .long("book")
                 .help("The Rust Programming Language book"))
            .arg(Arg::with_name("std")
                 .long("std")
                 .help("Standard library API documentation"))
            .group(ArgGroup::with_name("page")
                 .args(&["book", "std"]))
        )
        .subcommand(SubCommand::with_name("self")
            .about("Modify the rustup installation")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("update")
                .about("Download and install updates to rustup"))
            .subcommand(SubCommand::with_name("uninstall")
                .about("Uninstall rustup.")
                .arg(Arg::with_name("no-prompt")
                     .short("y")))
            .subcommand(SubCommand::with_name("upgrade-data")
                .about("Upgrade the internal data format.")))
        .subcommand(SubCommand::with_name("telemetry")
            .about("rustup telemetry commands")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .subcommand(SubCommand::with_name("enable")
                            .about("Enable rustup telemetry"))
            .subcommand(SubCommand::with_name("disable")
                            .about("Disable rustup telemetry"))
            .subcommand(SubCommand::with_name("analyze")
                            .about("Analyze stored telemetry")))
}

fn maybe_upgrade_data(cfg: &Cfg, m: &ArgMatches) -> Result<bool> {
    match m.subcommand() {
        ("self", Some(c)) => {
            match c.subcommand() {
                ("upgrade-data", Some(_)) => {
                    try!(cfg.upgrade_data());
                    Ok(true)
                }
                _ => Ok(false),
            }
        }
        _ => Ok(false)
    }
}

fn default_(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let ref toolchain = try!(cfg.get_toolchain(toolchain, false));

    let status = if !toolchain.is_custom() {
        Some(try!(toolchain.install_from_dist_if_not_installed()))
    } else if !toolchain.exists() {
        return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
    } else {
        None
    };

    try!(toolchain.make_default());

    if let Some(status) = status {
        println!("");
        try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
    }

    Ok(())
}

fn update(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    if let Some(name) = m.value_of("toolchain") {
        let toolchain = try!(cfg.get_toolchain(name, false));

        let status = if !toolchain.is_custom() {
            Some(try!(toolchain.install_from_dist()))
        } else if !toolchain.exists() {
            return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
        } else {
            None
        };

        if let Some(status) = status {
            println!("");
            try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
        }
    } else {
        try!(common::update_all_channels(cfg, !m.is_present("no-self-update")));
    }

    Ok(())
}

fn run(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let args = m.values_of("command").unwrap();
    let args: Vec<_> = args.collect();
    let cmd = try!(cfg.create_command_for_toolchain(toolchain, args[0]));

    Ok(try!(command::run_command_for_dir(cmd, &args, &cfg)))
}

fn which(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let binary = m.value_of("command").expect("");

    let binary_path = try!(cfg.which_binary(&try!(utils::current_dir()), binary))
                          .expect("binary not found");

    try!(utils::assert_is_file(&binary_path));

    println!("{}", binary_path.display());

    Ok(())
}

fn show(cfg: &Cfg) -> Result<()> {
    let ref cwd = try!(utils::current_dir());
    let override_ = try!(cfg.find_override(cwd));
    if let Some((toolchain, reason)) = override_ {
        println!("{} ({})", toolchain.name(), reason);
        return Ok(());
    }

    let toolchain = try!(cfg.find_default());
    if let Some(toolchain) = toolchain {
        println!("{} (default toolchain)", toolchain.name());
        return Ok(());
    }

    println!("no active toolchain");

    Ok(())
}

fn target_list(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));

    common::list_targets(&toolchain)
}

fn target_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));
    let target = m.value_of("target").expect("");
    let new_component = Component {
        pkg: "rust-std".to_string(),
        target: TargetTriple::from_str(target),
    };

    Ok(try!(toolchain.add_component(new_component)))
}

fn target_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let toolchain = try!(explicit_or_dir_toolchain(cfg, m));
    let target = m.value_of("target").expect("");
    let new_component = Component {
        pkg: "rust-std".to_string(),
        target: TargetTriple::from_str(target),
    };

    Ok(try!(toolchain.remove_component(new_component)))
}

fn explicit_or_dir_toolchain<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolchain<'a>> {
    let toolchain = m.value_of("toolchain");
    if let Some(toolchain) = toolchain {
        let toolchain = try!(cfg.get_toolchain(toolchain, false));
        return Ok(toolchain);
    }

    let ref cwd = try!(utils::current_dir());
    let (toolchain, _) = try!(cfg.toolchain_for_dir(cwd));

    Ok(toolchain)
}

fn toolchain_link(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let ref path = m.value_of("path").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, true));

    Ok(try!(toolchain.install_from_dir(Path::new(path), true)))
}

fn toolchain_remove(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, false));

    Ok(try!(toolchain.remove()))
}

fn override_add(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let ref toolchain = m.value_of("toolchain").expect("");
    let toolchain = try!(cfg.get_toolchain(toolchain, false));

    let status = if !toolchain.is_custom() {
        Some(try!(toolchain.install_from_dist_if_not_installed()))
    } else if !toolchain.exists() {
        return Err(ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into());
    } else {
        None
    };

    try!(toolchain.make_override(&try!(utils::current_dir())));

    if let Some(status) = status {
        println!("");
        try!(common::show_channel_update(cfg, toolchain.name(), Ok(status)));
    }

    Ok(())
}

fn override_remove(cfg: &Cfg) -> Result<()> {
    let ref path = try!(utils::current_dir());

    let ref override_db = cfg.override_db;
    let notify_handler = cfg.notify_handler.as_ref();

    if try!(override_db.find(path, notify_handler)).is_none() {
        info!("no override toolchain for '{}'", path.display());
        return Ok(());
    }

    try!(override_db.remove(path, &cfg.temp_cfg, notify_handler));
    info!("override toolchain for '{}' removed", path.display());
    Ok(())
}

fn doc(cfg: &Cfg, m: &ArgMatches) -> Result<()> {
    let doc_url = if m.is_present("book") {
        "book/index.html"
    } else if m.is_present("std") {
        "std/index.html"
    } else {
        "index.html"
    };

    Ok(try!(cfg.open_docs_for_dir(&try!(utils::current_dir()), doc_url)))
}

fn self_uninstall(m: &ArgMatches) -> Result<()> {
    let no_prompt = m.is_present("no-prompt");

    self_update::uninstall(no_prompt)
}

fn set_telemetry(cfg: &Cfg, t: TelemetryMode) -> Result<()> {
    match t {
        TelemetryMode::On => Ok(try!(cfg.set_telemetry(true))),
        TelemetryMode::Off => Ok(try!(cfg.set_telemetry(false))),
    }
}

fn analyze_telemetry(cfg: &Cfg) -> Result<()> {
    let analysis = try!(cfg.analyze_telemetry());
    common::show_telemetry(analysis)
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

use perlin_core::index::posting::DocId;
use query::{ChainedOperand, ToOperands};

mod stemmers;
pub mod integers;
mod stopword_filter;

pub use language::stopword_filter::StopwordFilter;
pub use language::stemmers::Stemmer;

/// The single central trait of the push-based splittable pipeline!
/// Any element in it can be called passing a typed and generic input and a common value
pub trait CanApply<Input> {
    type Output;
    fn apply(&mut self, Input);
}

pub struct AlphaNumericTokenizer<TCB> {
    cb: TCB
}
impl<TCB> AlphaNumericTokenizer<TCB> {
    pub fn create(cb: TCB) -> Self {
        AlphaNumericTokenizer{
            cb: cb
        }
    }
}
impl<'a, TCB> CanApply<&'a str> for AlphaNumericTokenizer<TCB>
    where TCB: CanApply<&'a str>
{
    type Output = TCB::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split(|c: char| !c.is_alphanumeric()) {
            self.cb.apply(token);
        }
    }
}

impl<'a, TCB> ToOperands<'a> for AlphaNumericTokenizer<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.cb.to_operands()
    }
}

pub struct Debugger<TCallback>
{
    callback: TCallback,
}
impl<TCallback> Debugger<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        Debugger{
            callback: callback
        }
    }
}

impl<TCallback, T: Debug> CanApply<T> for Debugger<TCallback>
    where TCallback: CanApply<T>
{
    type Output = TCallback::Output;

    fn apply(&mut self, input: T) {
        println!("{:?}", input);
        self.callback.apply(input);
    }
}

impl<'a, TCB> ToOperands<'a> for Debugger<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<ChainedOperand<'a>>
    {
        self.callback.to_operands()
    }
}

pub struct WhitespaceTokenizer<TCallback>
{
    callback: TCallback,
}

impl<TCallback> WhitespaceTokenizer<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        WhitespaceTokenizer {
            callback: callback
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for WhitespaceTokenizer<TCallback>
    where TCallback: CanApply<&'a str> {
    type Output = TCallback::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split_whitespace() {
            self.callback.apply(token);
        }
    }
}

impl<'a, TCallback> ToOperands<'a> for WhitespaceTokenizer<TCallback>
    where TCallback: ToOperands<'a> {
    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.callback.to_operands()
    }
}

pub struct LowercaseFilter<TCallback>
{
    callback: TCallback,
}

impl<TCallback> LowercaseFilter<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        LowercaseFilter{
            callback: callback,
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for LowercaseFilter<TCallback>
    where TCallback: CanApply<String>
{
    type Output = TCallback::Output;
    fn apply(&mut self, input: &str) {
        self.callback.apply(input.to_lowercase())
    }
}

impl<'a, TCallback> ToOperands<'a> for LowercaseFilter<TCallback>
    where TCallback: ToOperands<'a> {

    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.callback.to_operands()
    }
}

use perlin_core::index::Index;
use std::hash::Hash;

pub struct IndexerFunnel<'a, T: 'a + Hash + Eq>
{
    doc_id: DocId,
    index: &'a mut Index<T>
}

impl<'a, T: Hash + Eq> IndexerFunnel<'a, T> {
    pub fn create(doc_id: DocId, index: &'a mut Index<T>) -> Self {
        IndexerFunnel {
            doc_id: doc_id,
            index: index
        }
    }
}

impl<'a, TTerm: 'a + Debug + Hash + Ord + Eq> CanApply<TTerm> for IndexerFunnel<'a, TTerm>{

    type Output = TTerm;

    fn apply(&mut self, input: TTerm) {
        self.index.index_term(input, self.doc_id);
    }
}

#[macro_export]
macro_rules! inner_pipeline {
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     > $($x:tt)*) => {
        // >
        inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*)
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params) | [field]
    {
        $element::create($($param),+ ,
                         IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
                         inner_pipeline!(;$INDEX; ;$doc_id; ;$field_id; ($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params)
    {
        $element::create($($param),+ , inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element | [field]
    {
        $element::create(
            IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
            inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident $($x:tt)*) =>
    // ;doc_id; ;field_id; Element
    {
        $element::create(inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;) => {
        IndexerFunnel::create($doc_id, &mut $INDEX.$field)
    };
    () => {}
}

#[macro_export]
macro_rules! pipeline {
    ($field:ident $($x:tt)*) => {
        Box::new(move |doc_id, index, content| {
            use $crate::language::CanApply;
            use $crate::language::IndexerFunnel;
            use std::marker::PhantomData;
            let mut pipe = inner_pipeline!(;index; ;doc_id; ;$field; $($x)*);
            pipe.apply(content);
            PhantomData
        })
    }
}

<commit_msg>AlphaNumericTokenizer to not emit empty strings<commit_after>use std::fmt::Debug;

use perlin_core::index::posting::DocId;
use query::{ChainedOperand, ToOperands};

mod stemmers;
pub mod integers;
mod stopword_filter;

pub use language::stopword_filter::StopwordFilter;
pub use language::stemmers::Stemmer;

/// The single central trait of the push-based splittable pipeline!
/// Any element in it can be called passing a typed and generic input and a common value
pub trait CanApply<Input> {
    type Output;
    fn apply(&mut self, Input);
}

pub struct AlphaNumericTokenizer<TCB> {
    cb: TCB
}
impl<TCB> AlphaNumericTokenizer<TCB> {
    pub fn create(cb: TCB) -> Self {
        AlphaNumericTokenizer{
            cb: cb
        }
    }
}
impl<'a, TCB> CanApply<&'a str> for AlphaNumericTokenizer<TCB>
    where TCB: CanApply<&'a str>
{
    type Output = TCB::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split(|c: char| !c.is_alphanumeric()) {
            if !token.is_empty() {
                self.cb.apply(token);
            }
        }
    }
}

impl<'a, TCB> ToOperands<'a> for AlphaNumericTokenizer<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.cb.to_operands()
    }
}

pub struct Debugger<TCallback>
{
    callback: TCallback,
}
impl<TCallback> Debugger<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        Debugger{
            callback: callback
        }
    }
}

impl<TCallback, T: Debug> CanApply<T> for Debugger<TCallback>
    where TCallback: CanApply<T>
{
    type Output = TCallback::Output;

    fn apply(&mut self, input: T) {
        println!("{:?}", input);
        self.callback.apply(input);
    }
}

impl<'a, TCB> ToOperands<'a> for Debugger<TCB>
    where TCB: ToOperands<'a>
{
    fn to_operands(self) -> Vec<ChainedOperand<'a>>
    {
        self.callback.to_operands()
    }
}

pub struct WhitespaceTokenizer<TCallback>
{
    callback: TCallback,
}

impl<TCallback> WhitespaceTokenizer<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        WhitespaceTokenizer {
            callback: callback
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for WhitespaceTokenizer<TCallback>
    where TCallback: CanApply<&'a str> {
    type Output = TCallback::Output;
    fn apply(&mut self, input: &'a str) {
        for token in input.split_whitespace() {
            self.callback.apply(token);
        }
    }
}

impl<'a, TCallback> ToOperands<'a> for WhitespaceTokenizer<TCallback>
    where TCallback: ToOperands<'a> {
    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.callback.to_operands()
    }
}

pub struct LowercaseFilter<TCallback>
{
    callback: TCallback,
}

impl<TCallback> LowercaseFilter<TCallback> {
    pub fn create(callback: TCallback) -> Self {
        LowercaseFilter{
            callback: callback,
        }
    }
}

impl<'a, TCallback> CanApply<&'a str> for LowercaseFilter<TCallback>
    where TCallback: CanApply<String>
{
    type Output = TCallback::Output;
    fn apply(&mut self, input: &str) {
        self.callback.apply(input.to_lowercase())
    }
}

impl<'a, TCallback> ToOperands<'a> for LowercaseFilter<TCallback>
    where TCallback: ToOperands<'a> {

    fn to_operands(self) -> Vec<ChainedOperand<'a>> {
        self.callback.to_operands()
    }
}

use perlin_core::index::Index;
use std::hash::Hash;

pub struct IndexerFunnel<'a, T: 'a + Hash + Eq>
{
    doc_id: DocId,
    index: &'a mut Index<T>
}

impl<'a, T: Hash + Eq> IndexerFunnel<'a, T> {
    pub fn create(doc_id: DocId, index: &'a mut Index<T>) -> Self {
        IndexerFunnel {
            doc_id: doc_id,
            index: index
        }
    }
}

impl<'a, TTerm: 'a + Debug + Hash + Ord + Eq> CanApply<TTerm> for IndexerFunnel<'a, TTerm>{

    type Output = TTerm;

    fn apply(&mut self, input: TTerm) {
        self.index.index_term(input, self.doc_id);
    }
}

#[macro_export]
macro_rules! inner_pipeline {
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     > $($x:tt)*) => {
        // >
        inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*)
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params) | [field]
    {
        $element::create($($param),+ ,
                         IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
                         inner_pipeline!(;$INDEX; ;$doc_id; ;$field_id; ($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident($($param:expr),+) $($x:tt)*) =>
    // ;doc_id; ;field_id; Element(params)
    {
        $element::create($($param),+ , inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident | [$this_field:ident] $($x:tt)*) =>
    // ;doc_id; ;field_id; Element | [field]
    {
        $element::create(
            IndexerFunnel::create($doc_id, &mut $INDEX.$this_field),
            inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;
     $element:ident $($x:tt)*) =>
    // ;doc_id; ;field_id; Element
    {
        $element::create(inner_pipeline!(;$INDEX; ;$doc_id; ;$field; $($x)*))
    };
    (;$INDEX:ident; ;$doc_id:expr; ;$field:ident;) => {
        IndexerFunnel::create($doc_id, &mut $INDEX.$field)
    };
    () => {}
}

#[macro_export]
macro_rules! pipeline {
    ($field:ident $($x:tt)*) => {
        Box::new(move |doc_id, index, content| {
            use $crate::language::CanApply;
            use $crate::language::IndexerFunnel;
            use std::marker::PhantomData;
            let mut pipe = inner_pipeline!(;index; ;doc_id; ;$field; $($x)*);
            pipe.apply(content);
            PhantomData
        })
    }
}

<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]

#![desc = "protobuf implementation for rust"]
#![license = "BSD"]

extern crate sync;
extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;
pub use error::ProtobufIoError;
pub use error::ProtobufWireError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

mod misc;
mod zigzag;
mod hex;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test_root;
#[cfg(test)]
mod test;
#[cfg(test)]
mod text_format_test_data;
#[cfg(test)]
mod test_nonunique_enum;
#[cfg(test)]
mod test_ident;

// so `use protobuf::*` could work in descriptor mod
pub mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<commit_msg>protobuf::protobuf should not be public<commit_after>#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]

#![desc = "protobuf implementation for rust"]
#![license = "BSD"]

extern crate sync;
extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;
pub use error::ProtobufIoError;
pub use error::ProtobufWireError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

mod misc;
mod zigzag;
mod hex;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test_root;
#[cfg(test)]
mod test;
#[cfg(test)]
mod text_format_test_data;
#[cfg(test)]
mod test_nonunique_enum;
#[cfg(test)]
mod test_ident;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<|endoftext|>


<commit_before>use std::vec;
use std::slice;
use std::default::Default;
use std::iter::FromIterator;
use std::iter::IntoIterator;
use std::ops::Index;
use std::ops::IndexMut;
use std::cmp::Ordering;
use std::fmt;

use clear::Clear;

pub struct RepeatedField<T> {
    vec: Vec<T>,
    len: usize,
}

impl<T> RepeatedField<T> {
    #[inline]
    fn len(&self) -> usize {
        self.len
    }

    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Clear for RepeatedField<T> {
    #[inline]
    fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Default for RepeatedField<T> {
    #[inline]
    fn default() -> RepeatedField<T> {
        RepeatedField {
            vec: Vec::new(),
            len: 0,
        }
    }
}

impl<T> RepeatedField<T> {
    #[inline]
    pub fn new() -> RepeatedField<T> {
        Default::default()
    }

    #[inline]
    pub fn from_vec(vec: Vec<T>) -> RepeatedField<T> {
        let len = vec.len();
        RepeatedField {
            vec: vec,
            len: len,
        }
    }

    #[inline]
    pub fn into_vec(self) -> Vec<T> {
        let mut vec = self.vec;
        vec.truncate(self.len);
        vec
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.vec.capacity()
    }

    #[inline]
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        self.vec.as_mut_slice()
    }

    #[inline]
    pub fn slice<'a>(&'a self, start: usize, end: usize) -> &'a [T] {
        &self.as_slice()[start..end]
    }

    #[inline]
    pub fn slice_mut<'a>(&'a mut self, start: usize, end: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[start..end]
    }

    #[inline]
    pub fn slice_from<'a>(&'a self, start: usize) -> &'a [T] {
        &self.as_slice()[start..]
    }

    #[inline]
    pub fn slice_from_mut<'a>(&'a mut self, start: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[start..]
    }

    #[inline]
    pub fn slice_to<'a>(&'a self, end: usize) -> &'a [T] {
        &self.as_slice()[..end]
    }

    #[inline]
    pub fn slice_to_mut<'a>(&'a mut self, end: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[..end]
    }

    #[inline]
    pub fn split_at<'a>(&'a self, mid: usize) -> (&'a [T], &'a [T]) {
        self.as_slice().split_at(mid)
    }

    #[inline]
    pub fn split_at_mut<'a>(&'a mut self, mid: usize) -> (&'a mut [T], &'a mut [T]) {
        self.as_mut_slice().split_at_mut(mid)
    }

    #[inline]
    pub fn tail<'a>(&'a self) -> &'a [T] {
        self.as_slice().tail()
    }

    #[inline]
    pub fn last<'a>(&'a self) -> Option<&'a T> {
        self.as_slice().last()
    }

    #[inline]
    pub fn last_mut<'a>(&'a mut self) -> Option<&'a mut T> {
        self.as_mut_slice().last_mut()
    }

    #[inline]
    pub fn init<'a>(&'a self) -> &'a [T] {
        self.as_slice().init()
    }

    #[inline]
    pub fn push(&mut self, value: T) {
        if self.len == self.vec.len() {
            self.vec.push(value);
        } else {
            self.vec[self.len] = value;
        }
        self.len += 1;
    }

    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if self.len == 0 {
            None
        } else {
            self.vec.truncate(self.len);
            self.len -= 1;
            self.vec.pop()
        }
    }

    #[inline]
    pub fn insert(&mut self, index: usize, value: T) {
        assert!(index <= self.len);
        self.vec.insert(index, value);
        self.len += 1;
    }

    #[inline]
    pub fn remove(&mut self, index: usize) -> T {
        assert!(index < self.len);
        self.len -= 1;
        self.vec.remove(index)
    }

    #[inline]
    pub fn truncate(&mut self, len: usize) {
        if self.len > len {
            self.len = len;
        }
    }

    #[inline]
    pub fn reverse(&mut self) {
        self.as_mut_slice().reverse()
    }

    #[inline]
    pub fn into_iter(mut self) -> vec::IntoIter<T> {
        self.vec.truncate(self.len);
        self.vec.into_iter()
    }

    #[deprecated = "use `foo[index]` instead"]
    #[inline]
    pub fn get<'a>(&'a self, index: usize) -> &'a T {
        &self.as_slice()[index]
    }

    #[deprecated = "use `foo[index] = bar` instead"]
    #[inline]
    pub fn get_mut<'a>(&'a mut self, index: usize) -> &'a mut T {
        &mut self.as_mut_slice()[index]
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
        self.as_slice().iter()
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> slice::IterMut<'a, T> {
        self.as_mut_slice().iter_mut()
    }

    #[inline]
    pub fn sort_by<F>(&mut self, compare: F) where F: Fn(&T, &T) -> Ordering {
        self.as_mut_slice().sort_by(compare)
    }

    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.vec.as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.vec.as_mut_ptr()
    }
}

impl<T : Default+Clear> RepeatedField<T> {
    pub fn push_default<'a>(&'a mut self) -> &'a mut T {
        if self.len == self.vec.len() {
            self.vec.push(Default::default());
        } else {
            self.vec[self.len].clear();
        }
        self.len += 1;
        self.last_mut().unwrap()
    }
}

impl<T : Clone> RepeatedField<T> {
    // TODO: implement to_vec()
    #[inline]
    pub fn from_slice(values: &[T]) -> RepeatedField<T> {
        RepeatedField::from_vec(values.to_vec())
    }
}

impl<T : Clone> Clone for RepeatedField<T> {
    #[inline]
    fn clone(&self) -> RepeatedField<T> {
        RepeatedField {
            vec: self.as_slice().to_vec(),
            len: self.len(),
        }
    }
}

impl<T> FromIterator<T> for RepeatedField<T> {
    #[inline]
    fn from_iter<I : IntoIterator<Item = T>>(iter: I) -> RepeatedField<T> {
        RepeatedField::from_vec(FromIterator::from_iter(iter))
    }
}

impl<T : PartialEq> PartialEq for RepeatedField<T> {
    #[inline]
    fn eq(&self, other: &RepeatedField<T>) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<T : Eq> Eq for RepeatedField<T> {}

impl<T : PartialEq> RepeatedField<T> {
    #[inline]
    pub fn contains(&self, value: &T) -> bool {
        self.as_slice().contains(value)
    }
}

impl<T> AsSlice<T> for RepeatedField<T> {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a [T] {
        &self.vec[..self.len]
    }
}

impl<T> Index<usize> for RepeatedField<T> {
    type Output = T;

    #[inline]
    fn index<'a>(&'a self, index: &usize) -> &'a T {
        &self.as_slice()[*index]
    }
}

impl<T> IndexMut<usize> for RepeatedField<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &usize) -> &'a mut T {
        &mut self.as_mut_slice()[*index]
    }
}

impl<T : fmt::Debug> fmt::Debug for RepeatedField<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}
<commit_msg>RepeatedField: implement Borrow, Deref and DerefMut<commit_after>use std::vec;
use std::slice;
use std::borrow::Borrow;
use std::default::Default;
use std::iter::FromIterator;
use std::iter::IntoIterator;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Deref;
use std::ops::DerefMut;
use std::cmp::Ordering;
use std::fmt;

use clear::Clear;

pub struct RepeatedField<T> {
    vec: Vec<T>,
    len: usize,
}

impl<T> RepeatedField<T> {
    #[inline]
    fn len(&self) -> usize {
        self.len
    }

    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Clear for RepeatedField<T> {
    #[inline]
    fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Default for RepeatedField<T> {
    #[inline]
    fn default() -> RepeatedField<T> {
        RepeatedField {
            vec: Vec::new(),
            len: 0,
        }
    }
}

impl<T> RepeatedField<T> {
    #[inline]
    pub fn new() -> RepeatedField<T> {
        Default::default()
    }

    #[inline]
    pub fn from_vec(vec: Vec<T>) -> RepeatedField<T> {
        let len = vec.len();
        RepeatedField {
            vec: vec,
            len: len,
        }
    }

    #[inline]
    pub fn into_vec(self) -> Vec<T> {
        let mut vec = self.vec;
        vec.truncate(self.len);
        vec
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.vec.capacity()
    }

    #[inline]
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        self.vec.as_mut_slice()
    }

    #[inline]
    pub fn slice<'a>(&'a self, start: usize, end: usize) -> &'a [T] {
        &self.as_slice()[start..end]
    }

    #[inline]
    pub fn slice_mut<'a>(&'a mut self, start: usize, end: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[start..end]
    }

    #[inline]
    pub fn slice_from<'a>(&'a self, start: usize) -> &'a [T] {
        &self.as_slice()[start..]
    }

    #[inline]
    pub fn slice_from_mut<'a>(&'a mut self, start: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[start..]
    }

    #[inline]
    pub fn slice_to<'a>(&'a self, end: usize) -> &'a [T] {
        &self.as_slice()[..end]
    }

    #[inline]
    pub fn slice_to_mut<'a>(&'a mut self, end: usize) -> &'a mut [T] {
        &mut self.as_mut_slice()[..end]
    }

    #[inline]
    pub fn split_at<'a>(&'a self, mid: usize) -> (&'a [T], &'a [T]) {
        self.as_slice().split_at(mid)
    }

    #[inline]
    pub fn split_at_mut<'a>(&'a mut self, mid: usize) -> (&'a mut [T], &'a mut [T]) {
        self.as_mut_slice().split_at_mut(mid)
    }

    #[inline]
    pub fn tail<'a>(&'a self) -> &'a [T] {
        self.as_slice().tail()
    }

    #[inline]
    pub fn last<'a>(&'a self) -> Option<&'a T> {
        self.as_slice().last()
    }

    #[inline]
    pub fn last_mut<'a>(&'a mut self) -> Option<&'a mut T> {
        self.as_mut_slice().last_mut()
    }

    #[inline]
    pub fn init<'a>(&'a self) -> &'a [T] {
        self.as_slice().init()
    }

    #[inline]
    pub fn push(&mut self, value: T) {
        if self.len == self.vec.len() {
            self.vec.push(value);
        } else {
            self.vec[self.len] = value;
        }
        self.len += 1;
    }

    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if self.len == 0 {
            None
        } else {
            self.vec.truncate(self.len);
            self.len -= 1;
            self.vec.pop()
        }
    }

    #[inline]
    pub fn insert(&mut self, index: usize, value: T) {
        assert!(index <= self.len);
        self.vec.insert(index, value);
        self.len += 1;
    }

    #[inline]
    pub fn remove(&mut self, index: usize) -> T {
        assert!(index < self.len);
        self.len -= 1;
        self.vec.remove(index)
    }

    #[inline]
    pub fn truncate(&mut self, len: usize) {
        if self.len > len {
            self.len = len;
        }
    }

    #[inline]
    pub fn reverse(&mut self) {
        self.as_mut_slice().reverse()
    }

    #[inline]
    pub fn into_iter(mut self) -> vec::IntoIter<T> {
        self.vec.truncate(self.len);
        self.vec.into_iter()
    }

    #[deprecated = "use `foo[index]` instead"]
    #[inline]
    pub fn get<'a>(&'a self, index: usize) -> &'a T {
        &self.as_slice()[index]
    }

    #[deprecated = "use `foo[index] = bar` instead"]
    #[inline]
    pub fn get_mut<'a>(&'a mut self, index: usize) -> &'a mut T {
        &mut self.as_mut_slice()[index]
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
        self.as_slice().iter()
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> slice::IterMut<'a, T> {
        self.as_mut_slice().iter_mut()
    }

    #[inline]
    pub fn sort_by<F>(&mut self, compare: F) where F: Fn(&T, &T) -> Ordering {
        self.as_mut_slice().sort_by(compare)
    }

    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.vec.as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.vec.as_mut_ptr()
    }
}

impl<T : Default+Clear> RepeatedField<T> {
    pub fn push_default<'a>(&'a mut self) -> &'a mut T {
        if self.len == self.vec.len() {
            self.vec.push(Default::default());
        } else {
            self.vec[self.len].clear();
        }
        self.len += 1;
        self.last_mut().unwrap()
    }
}

impl<T : Clone> RepeatedField<T> {
    // TODO: implement to_vec()
    #[inline]
    pub fn from_slice(values: &[T]) -> RepeatedField<T> {
        RepeatedField::from_vec(values.to_vec())
    }
}

impl<T : Clone> Clone for RepeatedField<T> {
    #[inline]
    fn clone(&self) -> RepeatedField<T> {
        RepeatedField {
            vec: self.as_slice().to_vec(),
            len: self.len(),
        }
    }
}

impl<T> FromIterator<T> for RepeatedField<T> {
    #[inline]
    fn from_iter<I : IntoIterator<Item = T>>(iter: I) -> RepeatedField<T> {
        RepeatedField::from_vec(FromIterator::from_iter(iter))
    }
}

impl<T : PartialEq> PartialEq for RepeatedField<T> {
    #[inline]
    fn eq(&self, other: &RepeatedField<T>) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<T : Eq> Eq for RepeatedField<T> {}

impl<T : PartialEq> RepeatedField<T> {
    #[inline]
    pub fn contains(&self, value: &T) -> bool {
        self.as_slice().contains(value)
    }
}

impl<T> AsSlice<T> for RepeatedField<T> {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a [T] {
        &self.vec[..self.len]
    }
}

impl<T> Borrow<[T]> for RepeatedField<T> {
    #[inline]
    fn borrow(&self) -> &[T] {
        &self.vec[..self.len]
    }
}

impl<T> Deref for RepeatedField<T> {
    type Target = [T];
    #[inline]
    fn deref(&self) -> &[T] {
        &self.vec[..self.len]
    }
}

impl<T> DerefMut for RepeatedField<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut [T] {
        &mut self.vec[..self.len]
    }
}

impl<T> Index<usize> for RepeatedField<T> {
    type Output = T;

    #[inline]
    fn index<'a>(&'a self, index: &usize) -> &'a T {
        &self.as_slice()[*index]
    }
}

impl<T> IndexMut<usize> for RepeatedField<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &usize) -> &'a mut T {
        &mut self.as_mut_slice()[*index]
    }
}

impl<T : fmt::Debug> fmt::Debug for RepeatedField<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}
<|endoftext|>


<commit_before>#[doc(
  brief = "Communication between tasks",
  desc  = "Communication between tasks is facilitated by ports (in the \
           receiving task), and channels (in the sending task). Any \
           number of channels may feed into a single port. \
           Ports and channels may only transmit values of unique \
           types; that is, values that are statically guaranteed to \
           be accessed by a single 'owner' at a time.  Unique types \
           include scalars, vectors, strings, and records, tags, \
           tuples and unique boxes (~T) thereof. Most notably, \
           shared boxes (@T) may not be transmitted across channels. \
           Example: \
               let p = comm::port(); \
               task::spawn(comm::chan(p), fn (c: chan<str>) { \
                   comm::send(c, \"Hello, World\"); \
               }); \
               io::println(comm::recv(p));"
)];

import sys;
import task;

export send;
export recv;
export chan;
export port;

#[abi = "cdecl"]
native mod rustrt {
    type rust_port;

    fn chan_id_send<T: send>(t: *sys::type_desc,
                            target_task: task::task, target_port: port_id,
                            data: T) -> ctypes::uintptr_t;

    fn new_port(unit_sz: uint) -> *rust_port;
    fn del_port(po: *rust_port);
    fn rust_port_detach(po: *rust_port);
    fn get_port_id(po: *rust_port) -> port_id;
    fn rust_port_size(po: *rust_port) -> ctypes::size_t;
    fn port_recv(dptr: *uint, po: *rust_port,
                 yield: *ctypes::uintptr_t,
                 killed: *ctypes::uintptr_t);
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn call_with_retptr<T: send>(&&f: fn@(*uint)) -> T;
}

type port_id = int;

// It's critical that this only have one variant, so it has a record
// layout, and will work in the rust_task structure in task.rs.
#[doc(
  brief = "A communication endpoint that can send messages.\
           Channels send messages to ports.",
  desc = "Each channel is bound to a port when the channel is\
          constructed, so the destination port for a channel\
          must exist before the channel itself.\
          Channels are weak: a channel does not keep the port it\
          is bound to alive. If a channel attempts to send data\
          to a dead port that data will be silently dropped.\
          Channels may be duplicated and themselves transmitted\
          over other channels."
)]
tag chan<T: send> {
    chan_t(task::task, port_id);
}

resource port_ptr<T: send>(po: *rustrt::rust_port) {
    // Once the port is detached it's guaranteed not to receive further
    // messages
    rustrt::rust_port_detach(po);
    // Drain the port so that all the still-enqueued items get dropped
    while rustrt::rust_port_size(po) > 0u {
        // FIXME: For some reason if we don't assign to something here
        // we end up with invalid reads in the drop glue.
        let _t = recv_::<T>(po);
    }
    rustrt::del_port(po);
}

#[doc(
  brief = "A communication endpoint that can receive messages. \
           Ports receive messages from channels.",
  desc = "Each port has a unique per-task identity and may not \
          be replicated or transmitted. If a port value is \
          copied, both copies refer to the same port. \
          Ports may be associated with multiple <chan>s."
)]
tag port<T: send> { port_t(@port_ptr<T>); }

#[doc(
  brief = "Sends data over a channel. The sent data is moved \
           into the channel, whereupon the caller loses \
           access to it."
)]
fn send<T: send>(ch: chan<T>, -data: T) {
    let chan_t(t, p) = ch;
    let res = rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data);
    if res != 0u unsafe {
        // Data sent successfully
        unsafe::leak(data);
    }
    task::yield();
}

#[doc(
  brief = "Constructs a port."
)]
fn port<T: send>() -> port<T> {
    port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
}

#[doc(
  brief = "Receive from a port. \
           If no data is available on the port then the task will \
           block until data becomes available."
)]
fn recv<T: send>(p: port<T>) -> T { recv_(***p) }

#[doc(
  brief = "Receive on a raw port pointer"
)]
fn recv_<T: send>(p: *rustrt::rust_port) -> T {
    // FIXME: Due to issue 1185 we can't use a return pointer when
    // calling C code, and since we can't create our own return
    // pointer on the stack, we're going to call a little intrinsic
    // that will grab the value of the return pointer, then call this
    // function, which we will then use to call the runtime.
    fn recv(dptr: *uint, port: *rustrt::rust_port,
            yield: *ctypes::uintptr_t,
            killed: *ctypes::uintptr_t) unsafe {
        rustrt::port_recv(dptr, port, yield, killed);
    }
    let yield = 0u;
    let yieldp = ptr::addr_of(yield);
    let killed = 0u;
    let killedp = ptr::addr_of(killed);
    let res = rusti::call_with_retptr(bind recv(_, p, yieldp, killedp));
    if killed != 0u {
        fail "killed";
    }
    if yield != 0u {
        // Data isn't available yet, so res has not been initialized.
        task::yield();
    }
    ret res;
}

#[doc(
  brief = "Constructs a channel. The channel is bound to the\
           port used to construct it."
)]
fn chan<T: send>(p: port<T>) -> chan<T> {
    chan_t(task::get_task(), rustrt::get_port_id(***p))
}
<commit_msg>Forgot to add some spaces before backslashes<commit_after>#[doc(
  brief = "Communication between tasks",
  desc  = "Communication between tasks is facilitated by ports (in the \
           receiving task), and channels (in the sending task). Any \
           number of channels may feed into a single port. \
           Ports and channels may only transmit values of unique \
           types; that is, values that are statically guaranteed to \
           be accessed by a single 'owner' at a time.  Unique types \
           include scalars, vectors, strings, and records, tags, \
           tuples and unique boxes (~T) thereof. Most notably, \
           shared boxes (@T) may not be transmitted across channels. \
           Example: \
               let p = comm::port(); \
               task::spawn(comm::chan(p), fn (c: chan<str>) { \
                   comm::send(c, \"Hello, World\"); \
               }); \
               io::println(comm::recv(p));"
)];

import sys;
import task;

export send;
export recv;
export chan;
export port;

#[abi = "cdecl"]
native mod rustrt {
    type rust_port;

    fn chan_id_send<T: send>(t: *sys::type_desc,
                            target_task: task::task, target_port: port_id,
                            data: T) -> ctypes::uintptr_t;

    fn new_port(unit_sz: uint) -> *rust_port;
    fn del_port(po: *rust_port);
    fn rust_port_detach(po: *rust_port);
    fn get_port_id(po: *rust_port) -> port_id;
    fn rust_port_size(po: *rust_port) -> ctypes::size_t;
    fn port_recv(dptr: *uint, po: *rust_port,
                 yield: *ctypes::uintptr_t,
                 killed: *ctypes::uintptr_t);
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn call_with_retptr<T: send>(&&f: fn@(*uint)) -> T;
}

type port_id = int;

// It's critical that this only have one variant, so it has a record
// layout, and will work in the rust_task structure in task.rs.
#[doc(
  brief = "A communication endpoint that can send messages. \
           Channels send messages to ports.",
  desc = "Each channel is bound to a port when the channel is \
          constructed, so the destination port for a channel \
          must exist before the channel itself. \
          Channels are weak: a channel does not keep the port it \
          is bound to alive. If a channel attempts to send data \
          to a dead port that data will be silently dropped. \
          Channels may be duplicated and themselves transmitted \
          over other channels."
)]
tag chan<T: send> {
    chan_t(task::task, port_id);
}

resource port_ptr<T: send>(po: *rustrt::rust_port) {
    // Once the port is detached it's guaranteed not to receive further
    // messages
    rustrt::rust_port_detach(po);
    // Drain the port so that all the still-enqueued items get dropped
    while rustrt::rust_port_size(po) > 0u {
        // FIXME: For some reason if we don't assign to something here
        // we end up with invalid reads in the drop glue.
        let _t = recv_::<T>(po);
    }
    rustrt::del_port(po);
}

#[doc(
  brief = "A communication endpoint that can receive messages. \
           Ports receive messages from channels.",
  desc = "Each port has a unique per-task identity and may not \
          be replicated or transmitted. If a port value is \
          copied, both copies refer to the same port. \
          Ports may be associated with multiple <chan>s."
)]
tag port<T: send> { port_t(@port_ptr<T>); }

#[doc(
  brief = "Sends data over a channel. The sent data is moved \
           into the channel, whereupon the caller loses \
           access to it."
)]
fn send<T: send>(ch: chan<T>, -data: T) {
    let chan_t(t, p) = ch;
    let res = rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data);
    if res != 0u unsafe {
        // Data sent successfully
        unsafe::leak(data);
    }
    task::yield();
}

#[doc(
  brief = "Constructs a port."
)]
fn port<T: send>() -> port<T> {
    port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
}

#[doc(
  brief = "Receive from a port. \
           If no data is available on the port then the task will \
           block until data becomes available."
)]
fn recv<T: send>(p: port<T>) -> T { recv_(***p) }

#[doc(
  brief = "Receive on a raw port pointer"
)]
fn recv_<T: send>(p: *rustrt::rust_port) -> T {
    // FIXME: Due to issue 1185 we can't use a return pointer when
    // calling C code, and since we can't create our own return
    // pointer on the stack, we're going to call a little intrinsic
    // that will grab the value of the return pointer, then call this
    // function, which we will then use to call the runtime.
    fn recv(dptr: *uint, port: *rustrt::rust_port,
            yield: *ctypes::uintptr_t,
            killed: *ctypes::uintptr_t) unsafe {
        rustrt::port_recv(dptr, port, yield, killed);
    }
    let yield = 0u;
    let yieldp = ptr::addr_of(yield);
    let killed = 0u;
    let killedp = ptr::addr_of(killed);
    let res = rusti::call_with_retptr(bind recv(_, p, yieldp, killedp));
    if killed != 0u {
        fail "killed";
    }
    if yield != 0u {
        // Data isn't available yet, so res has not been initialized.
        task::yield();
    }
    ret res;
}

#[doc(
  brief = "Constructs a channel. The channel is bound to the \
           port used to construct it."
)]
fn chan<T: send>(p: port<T>) -> chan<T> {
    chan_t(task::get_task(), rustrt::get_port_id(***p))
}
<|endoftext|>


<commit_before>
<commit_msg>remove macro mod<commit_after><|endoftext|>


<commit_before>//! Abstractions for default-sized and huge virtual memory pages.

use crate::structures::paging::page_table::PageTableLevel;
use crate::structures::paging::PageTableIndex;
use crate::VirtAddr;
use core::fmt;
#[cfg(feature = "step_trait")]
use core::iter::Step;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};

/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB.
pub trait PageSize: Copy + Eq + PartialOrd + Ord {
    /// The page size in bytes.
    const SIZE: u64;

    /// A string representation of the page size for debug output.
    const SIZE_AS_DEBUG_STR: &'static str;
}

/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages.
pub trait NotGiantPageSize: PageSize {}

/// A standard 4KiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size4KiB {}

/// A “huge” 2MiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size2MiB {}

/// A “giant” 1GiB page.
///
/// (Only available on newer x86_64 CPUs.)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size1GiB {}

impl PageSize for Size4KiB {
    const SIZE: u64 = 4096;
    const SIZE_AS_DEBUG_STR: &'static str = "4KiB";
}

impl NotGiantPageSize for Size4KiB {}

impl PageSize for Size2MiB {
    const SIZE: u64 = Size4KiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "2MiB";
}

impl NotGiantPageSize for Size2MiB {}

impl PageSize for Size1GiB {
    const SIZE: u64 = Size2MiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "1GiB";
}

/// A virtual memory page.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct Page<S: PageSize = Size4KiB> {
    start_address: VirtAddr,
    size: PhantomData<S>,
}

impl<S: PageSize> Page<S> {
    /// The page size in bytes.
    pub const SIZE: u64 = S::SIZE;

    /// Returns the page that starts at the given virtual address.
    ///
    /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start).
    #[inline]
    pub fn from_start_address(address: VirtAddr) -> Result<Self, AddressNotAligned> {
        if !address.is_aligned(S::SIZE) {
            return Err(AddressNotAligned);
        }
        Ok(Page::containing_address(address))
    }

    const_fn! {
        /// Returns the page that starts at the given virtual address.
        ///
        /// ## Safety
        ///
        /// The address must be correctly aligned.
        #[inline]
        pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
            Page {
                start_address,
                size: PhantomData,
            }
        }
    }

    /// Returns the page that contains the given virtual address.
    #[inline]
    pub fn containing_address(address: VirtAddr) -> Self {
        Page {
            start_address: address.align_down(S::SIZE),
            size: PhantomData,
        }
    }

    const_fn! {
        /// Returns the start address of the page.
        #[inline]
        pub fn start_address(self) -> VirtAddr {
            self.start_address
        }
    }

    const_fn! {
        /// Returns the size the page (4KB, 2MB or 1GB).
        #[inline]
        pub fn size(self) -> u64 {
            S::SIZE
        }
    }

    const_fn! {
        /// Returns the level 4 page table index of this page.
        #[inline]
        pub fn p4_index(self) -> PageTableIndex {
            self.start_address().p4_index()
        }
    }

    const_fn! {
        /// Returns the level 3 page table index of this page.
        #[inline]
        pub fn p3_index(self) -> PageTableIndex {
            self.start_address().p3_index()
        }
    }

    const_fn! {
        /// Returns the table index of this page at the specified level.
        #[inline]
        pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
            self.start_address().page_table_index(level)
        }
    }

    const_fn! {
        /// Returns a range of pages, exclusive `end`.
        #[inline]
        pub fn range(start: Self, end: Self) -> PageRange<S> {
            PageRange { start, end }
        }
    }

    const_fn! {
        /// Returns a range of pages, inclusive `end`.
        #[inline]
        pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
            PageRangeInclusive { start, end }
        }
    }
}

impl<S: NotGiantPageSize> Page<S> {
    const_fn! {
        /// Returns the level 2 page table index of this page.
        #[inline]
        pub fn p2_index(self) -> PageTableIndex {
            self.start_address().p2_index()
        }
    }
}

impl Page<Size1GiB> {
    /// Returns the 1GiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_1gib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size2MiB> {
    /// Returns the 2MiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_2mib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size4KiB> {
    /// Returns the 4KiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
        p1_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the level 1 page table index of this page.
    #[inline]
    pub const fn p1_index(self) -> PageTableIndex {
        self.start_address.p1_index()
    }
}

impl<S: PageSize> fmt::Debug for Page<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!(
            "Page[{}]({:#x})",
            S::SIZE_AS_DEBUG_STR,
            self.start_address().as_u64()
        ))
    }
}

impl<S: PageSize> Add<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * S::SIZE)
    }
}

impl<S: PageSize> AddAssign<u64> for Page<S> {
    #[inline]
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl<S: PageSize> Sub<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * S::SIZE)
    }
}

impl<S: PageSize> SubAssign<u64> for Page<S> {
    #[inline]
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl<S: PageSize> Sub<Self> for Page<S> {
    type Output = u64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        (self.start_address - rhs.start_address) / S::SIZE
    }
}

#[cfg(feature = "step_trait")]
impl<S: PageSize> Step for Page<S> {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        Step::steps_between(&start.start_address, &end.start_address)
            .map(|steps| steps / S::SIZE as usize)
    }

    fn forward_checked(start: Self, count: usize) -> Option<Self> {
        let count = count.checked_mul(S::SIZE as usize)?;
        let start_address = Step::forward_checked(start.start_address, count)?;
        Some(Self {
            start_address,
            size: PhantomData,
        })
    }

    fn backward_checked(start: Self, count: usize) -> Option<Self> {
        let count = count.checked_mul(S::SIZE as usize)?;
        let start_address = Step::backward_checked(start.start_address, count)?;
        Some(Self {
            start_address,
            size: PhantomData,
        })
    }
}

/// A range of pages with exclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct PageRange<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, exclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRange<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start >= self.end
    }
}

impl<S: PageSize> Iterator for PageRange<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start < self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl PageRange<Size2MiB> {
    /// Converts the range of 2MiB pages to a range of 4KiB pages.
    #[inline]
    pub fn as_4kib_page_range(self) -> PageRange<Size4KiB> {
        PageRange {
            start: Page::containing_address(self.start.start_address()),
            end: Page::containing_address(self.end.start_address()),
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRange<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRange")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// A range of pages with inclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct PageRangeInclusive<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, inclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRangeInclusive<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start > self.end
    }
}

impl<S: PageSize> Iterator for PageRangeInclusive<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start <= self.end {
            let page = self.start;

            // If the end of the inclusive range is the maximum page possible for size S,
            // incrementing start until it is greater than the end will cause an integer overflow.
            // So instead, in that case we decrement end rather than incrementing start.
            let max_page_addr = VirtAddr::new(u64::MAX) - (S::SIZE - 1);
            if self.start.start_address() < max_page_addr {
                self.start += 1;
            } else {
                self.end -= 1;
            }
            Some(page)
        } else {
            None
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRangeInclusive<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRangeInclusive")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// The given address was not sufficiently aligned.
#[derive(Debug)]
pub struct AddressNotAligned;

impl fmt::Display for AddressNotAligned {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "the given address was not sufficiently aligned")
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(0xdead_beaf);
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range = Page::range(start, end);
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }

    #[test]
    pub fn test_max_page_overflow() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(u64::MAX).align_down(page_size) - number * page_size;
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<commit_msg>Updated name of PageRangeInclusive overflow test<commit_after>//! Abstractions for default-sized and huge virtual memory pages.

use crate::structures::paging::page_table::PageTableLevel;
use crate::structures::paging::PageTableIndex;
use crate::VirtAddr;
use core::fmt;
#[cfg(feature = "step_trait")]
use core::iter::Step;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};

/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB.
pub trait PageSize: Copy + Eq + PartialOrd + Ord {
    /// The page size in bytes.
    const SIZE: u64;

    /// A string representation of the page size for debug output.
    const SIZE_AS_DEBUG_STR: &'static str;
}

/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages.
pub trait NotGiantPageSize: PageSize {}

/// A standard 4KiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size4KiB {}

/// A “huge” 2MiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size2MiB {}

/// A “giant” 1GiB page.
///
/// (Only available on newer x86_64 CPUs.)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size1GiB {}

impl PageSize for Size4KiB {
    const SIZE: u64 = 4096;
    const SIZE_AS_DEBUG_STR: &'static str = "4KiB";
}

impl NotGiantPageSize for Size4KiB {}

impl PageSize for Size2MiB {
    const SIZE: u64 = Size4KiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "2MiB";
}

impl NotGiantPageSize for Size2MiB {}

impl PageSize for Size1GiB {
    const SIZE: u64 = Size2MiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "1GiB";
}

/// A virtual memory page.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct Page<S: PageSize = Size4KiB> {
    start_address: VirtAddr,
    size: PhantomData<S>,
}

impl<S: PageSize> Page<S> {
    /// The page size in bytes.
    pub const SIZE: u64 = S::SIZE;

    /// Returns the page that starts at the given virtual address.
    ///
    /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start).
    #[inline]
    pub fn from_start_address(address: VirtAddr) -> Result<Self, AddressNotAligned> {
        if !address.is_aligned(S::SIZE) {
            return Err(AddressNotAligned);
        }
        Ok(Page::containing_address(address))
    }

    const_fn! {
        /// Returns the page that starts at the given virtual address.
        ///
        /// ## Safety
        ///
        /// The address must be correctly aligned.
        #[inline]
        pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
            Page {
                start_address,
                size: PhantomData,
            }
        }
    }

    /// Returns the page that contains the given virtual address.
    #[inline]
    pub fn containing_address(address: VirtAddr) -> Self {
        Page {
            start_address: address.align_down(S::SIZE),
            size: PhantomData,
        }
    }

    const_fn! {
        /// Returns the start address of the page.
        #[inline]
        pub fn start_address(self) -> VirtAddr {
            self.start_address
        }
    }

    const_fn! {
        /// Returns the size the page (4KB, 2MB or 1GB).
        #[inline]
        pub fn size(self) -> u64 {
            S::SIZE
        }
    }

    const_fn! {
        /// Returns the level 4 page table index of this page.
        #[inline]
        pub fn p4_index(self) -> PageTableIndex {
            self.start_address().p4_index()
        }
    }

    const_fn! {
        /// Returns the level 3 page table index of this page.
        #[inline]
        pub fn p3_index(self) -> PageTableIndex {
            self.start_address().p3_index()
        }
    }

    const_fn! {
        /// Returns the table index of this page at the specified level.
        #[inline]
        pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
            self.start_address().page_table_index(level)
        }
    }

    const_fn! {
        /// Returns a range of pages, exclusive `end`.
        #[inline]
        pub fn range(start: Self, end: Self) -> PageRange<S> {
            PageRange { start, end }
        }
    }

    const_fn! {
        /// Returns a range of pages, inclusive `end`.
        #[inline]
        pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
            PageRangeInclusive { start, end }
        }
    }
}

impl<S: NotGiantPageSize> Page<S> {
    const_fn! {
        /// Returns the level 2 page table index of this page.
        #[inline]
        pub fn p2_index(self) -> PageTableIndex {
            self.start_address().p2_index()
        }
    }
}

impl Page<Size1GiB> {
    /// Returns the 1GiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_1gib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size2MiB> {
    /// Returns the 2MiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_2mib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size4KiB> {
    /// Returns the 4KiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
        p1_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the level 1 page table index of this page.
    #[inline]
    pub const fn p1_index(self) -> PageTableIndex {
        self.start_address.p1_index()
    }
}

impl<S: PageSize> fmt::Debug for Page<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!(
            "Page[{}]({:#x})",
            S::SIZE_AS_DEBUG_STR,
            self.start_address().as_u64()
        ))
    }
}

impl<S: PageSize> Add<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * S::SIZE)
    }
}

impl<S: PageSize> AddAssign<u64> for Page<S> {
    #[inline]
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl<S: PageSize> Sub<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * S::SIZE)
    }
}

impl<S: PageSize> SubAssign<u64> for Page<S> {
    #[inline]
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl<S: PageSize> Sub<Self> for Page<S> {
    type Output = u64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        (self.start_address - rhs.start_address) / S::SIZE
    }
}

#[cfg(feature = "step_trait")]
impl<S: PageSize> Step for Page<S> {
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        Step::steps_between(&start.start_address, &end.start_address)
            .map(|steps| steps / S::SIZE as usize)
    }

    fn forward_checked(start: Self, count: usize) -> Option<Self> {
        let count = count.checked_mul(S::SIZE as usize)?;
        let start_address = Step::forward_checked(start.start_address, count)?;
        Some(Self {
            start_address,
            size: PhantomData,
        })
    }

    fn backward_checked(start: Self, count: usize) -> Option<Self> {
        let count = count.checked_mul(S::SIZE as usize)?;
        let start_address = Step::backward_checked(start.start_address, count)?;
        Some(Self {
            start_address,
            size: PhantomData,
        })
    }
}

/// A range of pages with exclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct PageRange<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, exclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRange<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start >= self.end
    }
}

impl<S: PageSize> Iterator for PageRange<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start < self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl PageRange<Size2MiB> {
    /// Converts the range of 2MiB pages to a range of 4KiB pages.
    #[inline]
    pub fn as_4kib_page_range(self) -> PageRange<Size4KiB> {
        PageRange {
            start: Page::containing_address(self.start.start_address()),
            end: Page::containing_address(self.end.start_address()),
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRange<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRange")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// A range of pages with inclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct PageRangeInclusive<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, inclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRangeInclusive<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start > self.end
    }
}

impl<S: PageSize> Iterator for PageRangeInclusive<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start <= self.end {
            let page = self.start;

            // If the end of the inclusive range is the maximum page possible for size S,
            // incrementing start until it is greater than the end will cause an integer overflow.
            // So instead, in that case we decrement end rather than incrementing start.
            let max_page_addr = VirtAddr::new(u64::MAX) - (S::SIZE - 1);
            if self.start.start_address() < max_page_addr {
                self.start += 1;
            } else {
                self.end -= 1;
            }
            Some(page)
        } else {
            None
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRangeInclusive<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRangeInclusive")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// The given address was not sufficiently aligned.
#[derive(Debug)]
pub struct AddressNotAligned;

impl fmt::Display for AddressNotAligned {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "the given address was not sufficiently aligned")
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(0xdead_beaf);
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range = Page::range(start, end);
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }

    #[test]
    pub fn test_page_range_inclusive_overflow() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(u64::MAX).align_down(page_size) - number * page_size;
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<|endoftext|>