<commit_before>//! C-compiler probing and detection.
//!
//! This module will fill out the `cc` and `cxx` maps of `Build` by looking for
//! C and C++ compilers for each target configured. A compiler is found through
//! a number of vectors (in order of precedence)
//!
//! 1. Configuration via `target.$target.cc` in `config.toml`.
//! 2. Configuration via `target.$target.android-ndk` in `config.toml`, if
//!    applicable
//! 3. Special logic to probe on OpenBSD
//! 4. The `CC_$target` environment variable.
//! 5. The `CC` environment variable.
//! 6. "cc"
//!
//! Some of this logic is implemented here, but much of it is farmed out to the
//! `cc` crate itself, so we end up having the same fallbacks as there.
//! Similar logic is then used to find a C++ compiler, just some s/cc/c++/ is
//! used.
//!
//! It is intended that after this module has run no C/C++ compiler will
//! ever be probed for. Instead the compilers found here will be used for
//! everything.

use std::collections::HashSet;
use std::{env, iter};
use std::path::{Path, PathBuf};
use std::process::Command;

use build_helper::output;

use crate::{Build, GitRepo};
use crate::config::Target;
use crate::cache::Interned;

// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
// so use some simplified logic here. First we respect the environment variable `AR`, then
// try to infer the archiver path from the C compiler path.
// In the future this logic should be replaced by calling into the `cc` crate.
fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
    if let Some(ar) = env::var_os("AR") {
        Some(PathBuf::from(ar))
    } else if target.contains("msvc") {
        None
    } else if target.contains("musl") {
        Some(PathBuf::from("ar"))
    } else if target.contains("openbsd") {
        Some(PathBuf::from("ar"))
    } else {
        let parent = cc.parent().unwrap();
        let file = cc.file_name().unwrap().to_str().unwrap();
        for suffix in &["gcc", "cc", "clang"] {
            if let Some(idx) = file.rfind(suffix) {
                let mut file = file[..idx].to_owned();
                file.push_str("ar");
                return Some(parent.join(&file));
            }
        }
        Some(parent.join(file))
    }
}

pub fn find(build: &mut Build) {
    // For all targets we're going to need a C compiler for building some shims
    // and such as well as for being a linker for Rust code.
    let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build))
                               .collect::<HashSet<_>>();
    for target in targets.into_iter() {
        let mut cfg = cc::Build::new();
        cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false)
           .target(&target).host(&build.build);
        match build.crt_static(target) {
            Some(a) => { cfg.static_crt(a); }
            None => {
                if target.contains("msvc") {
                    cfg.static_crt(true);
                }
                if target.contains("musl") {
                    cfg.static_flag(true);
                }
            }
        }

        let config = build.config.target_config.get(&target);
        if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
            cfg.compiler(cc);
        } else {
            set_compiler(&mut cfg, Language::C, target, config, build);
        }

        let compiler = cfg.get_compiler();
        let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
            ar
        } else {
            cc2ar(compiler.path(), &target)
        };

        build.cc.insert(target, compiler);
        let cflags = build.cflags(target, GitRepo::Rustc);

        // If we use llvm-libunwind, we will need a C++ compiler as well for all targets
        // We'll need one anyways if the target triple is also a host triple
        let mut cfg = cc::Build::new();
        cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true)
            .target(&target).host(&build.build);

        let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
            cfg.compiler(cxx);
            true
        } else {
            set_compiler(&mut cfg, Language::CPlusPlus, target, config, build)
        };

        if cxx_configured || build.hosts.contains(&target) {
            let compiler = cfg.get_compiler();
            build.cxx.insert(target, compiler);
        }

        build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
        build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags));
        if let Ok(cxx) = build.cxx(target) {
            build.verbose(&format!("CXX_{} = {:?}", &target, cxx));
            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags));
        }
        if let Some(ar) = ar {
            build.verbose(&format!("AR_{} = {:?}", &target, ar));
            build.ar.insert(target, ar);
        }
    }
}

fn set_compiler(cfg: &mut cc::Build,
                compiler: Language,
                target: Interned<String>,
                config: Option<&Target>,
                build: &Build) -> bool {
    match &*target {
        // When compiling for android we may have the NDK configured in the
        // config.toml in which case we look there. Otherwise the default
        // compiler already takes into account the triple in question.
        t if t.contains("android") => {
            if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
                let target = target.replace("armv7neon", "arm")
                                   .replace("armv7", "arm")
                                   .replace("thumbv7neon", "arm")
                                   .replace("thumbv7", "arm");
                let compiler = format!("{}-{}", target, compiler.clang());
                cfg.compiler(ndk.join("bin").join(compiler));
                return true;
            }
        }

        // The default gcc version from OpenBSD may be too old, try using egcc,
        // which is a gcc version from ports, if this is the case.
        t if t.contains("openbsd") => {
            let c = cfg.get_compiler();
            let gnu_compiler = compiler.gcc();
            if !c.path().ends_with(gnu_compiler) {
                return false;
            }

            let output = output(c.to_command().arg("--version"));
            let i = match output.find(" 4.") {
                Some(i) => i,
                None => return false,
            };
            match output[i + 3..].chars().next().unwrap() {
                '0' ..= '6' => {}
                _ => return false,
            }
            let alternative = format!("e{}", gnu_compiler);
            if Command::new(&alternative).output().is_ok() {
                cfg.compiler(alternative);
                return true;
            }
        }

        "mips-unknown-linux-musl" => {
            if cfg.get_compiler().path().to_str() == Some("gcc") {
                cfg.compiler("mips-linux-musl-gcc");
                return true;
            }
        }
        "mipsel-unknown-linux-musl" => {
            if cfg.get_compiler().path().to_str() == Some("gcc") {
                cfg.compiler("mipsel-linux-musl-gcc");
                return true;
            }
        }

        t if t.contains("musl") => {
            if let Some(root) = build.musl_root(target) {
                let guess = root.join("bin/musl-gcc");
                if guess.exists() {
                    cfg.compiler(guess);
                    return true;
                }
            }
        }

        _ => {}
    }
    false
}

/// The target programming language for a native compiler.
enum Language {
    /// The compiler is targeting C.
    C,
    /// The compiler is targeting C++.
    CPlusPlus,
}

impl Language {
    /// Obtains the name of a compiler in the GCC collection.
    fn gcc(self) -> &'static str {
        match self {
            Language::C => "gcc",
            Language::CPlusPlus => "g++",
        }
    }

    /// Obtains the name of a compiler in the clang suite.
    fn clang(self) -> &'static str {
        match self {
            Language::C => "clang",
            Language::CPlusPlus => "clang++",
        }
    }
}
<commit_msg>rustbuild: only autodetect cxx for hosts<commit_after>//! C-compiler probing and detection.
//!
//! This module will fill out the `cc` and `cxx` maps of `Build` by looking for
//! C and C++ compilers for each target configured. A compiler is found through
//! a number of vectors (in order of precedence)
//!
//! 1. Configuration via `target.$target.cc` in `config.toml`.
//! 2. Configuration via `target.$target.android-ndk` in `config.toml`, if
//!    applicable
//! 3. Special logic to probe on OpenBSD
//! 4. The `CC_$target` environment variable.
//! 5. The `CC` environment variable.
//! 6. "cc"
//!
//! Some of this logic is implemented here, but much of it is farmed out to the
//! `cc` crate itself, so we end up having the same fallbacks as there.
//! Similar logic is then used to find a C++ compiler, just some s/cc/c++/ is
//! used.
//!
//! It is intended that after this module has run no C/C++ compiler will
//! ever be probed for. Instead the compilers found here will be used for
//! everything.

use std::collections::HashSet;
use std::{env, iter};
use std::path::{Path, PathBuf};
use std::process::Command;

use build_helper::output;

use crate::{Build, GitRepo};
use crate::config::Target;
use crate::cache::Interned;

// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
// so use some simplified logic here. First we respect the environment variable `AR`, then
// try to infer the archiver path from the C compiler path.
// In the future this logic should be replaced by calling into the `cc` crate.
fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
    if let Some(ar) = env::var_os("AR") {
        Some(PathBuf::from(ar))
    } else if target.contains("msvc") {
        None
    } else if target.contains("musl") {
        Some(PathBuf::from("ar"))
    } else if target.contains("openbsd") {
        Some(PathBuf::from("ar"))
    } else {
        let parent = cc.parent().unwrap();
        let file = cc.file_name().unwrap().to_str().unwrap();
        for suffix in &["gcc", "cc", "clang"] {
            if let Some(idx) = file.rfind(suffix) {
                let mut file = file[..idx].to_owned();
                file.push_str("ar");
                return Some(parent.join(&file));
            }
        }
        Some(parent.join(file))
    }
}

pub fn find(build: &mut Build) {
    // For all targets we're going to need a C compiler for building some shims
    // and such as well as for being a linker for Rust code.
    let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build))
                               .collect::<HashSet<_>>();
    for target in targets.into_iter() {
        let mut cfg = cc::Build::new();
        cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false)
           .target(&target).host(&build.build);
        match build.crt_static(target) {
            Some(a) => { cfg.static_crt(a); }
            None => {
                if target.contains("msvc") {
                    cfg.static_crt(true);
                }
                if target.contains("musl") {
                    cfg.static_flag(true);
                }
            }
        }

        let config = build.config.target_config.get(&target);
        if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
            cfg.compiler(cc);
        } else {
            set_compiler(&mut cfg, Language::C, target, config, build);
        }

        let compiler = cfg.get_compiler();
        let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
            ar
        } else {
            cc2ar(compiler.path(), &target)
        };

        build.cc.insert(target, compiler);
        let cflags = build.cflags(target, GitRepo::Rustc);

        // If we use llvm-libunwind, we will need a C++ compiler as well for all targets
        // We'll need one anyways if the target triple is also a host triple
        let mut cfg = cc::Build::new();
        cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true)
            .target(&target).host(&build.build);

        let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
            cfg.compiler(cxx);
            true
        } else if build.hosts.contains(&target) {
            set_compiler(&mut cfg, Language::CPlusPlus, target, config, build);
            true
        } else {
            false
        };

        if cxx_configured {
            let compiler = cfg.get_compiler();
            build.cxx.insert(target, compiler);
        }

        build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
        build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags));
        if let Ok(cxx) = build.cxx(target) {
            build.verbose(&format!("CXX_{} = {:?}", &target, cxx));
            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags));
        }
        if let Some(ar) = ar {
            build.verbose(&format!("AR_{} = {:?}", &target, ar));
            build.ar.insert(target, ar);
        }
    }
}

fn set_compiler(cfg: &mut cc::Build,
                compiler: Language,
                target: Interned<String>,
                config: Option<&Target>,
                build: &Build) {
    match &*target {
        // When compiling for android we may have the NDK configured in the
        // config.toml in which case we look there. Otherwise the default
        // compiler already takes into account the triple in question.
        t if t.contains("android") => {
            if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
                let target = target.replace("armv7neon", "arm")
                                   .replace("armv7", "arm")
                                   .replace("thumbv7neon", "arm")
                                   .replace("thumbv7", "arm");
                let compiler = format!("{}-{}", target, compiler.clang());
                cfg.compiler(ndk.join("bin").join(compiler));
            }
        }

        // The default gcc version from OpenBSD may be too old, try using egcc,
        // which is a gcc version from ports, if this is the case.
        t if t.contains("openbsd") => {
            let c = cfg.get_compiler();
            let gnu_compiler = compiler.gcc();
            if !c.path().ends_with(gnu_compiler) {
                return
            }

            let output = output(c.to_command().arg("--version"));
            let i = match output.find(" 4.") {
                Some(i) => i,
                None => return,
            };
            match output[i + 3..].chars().next().unwrap() {
                '0' ..= '6' => {}
                _ => return,
            }
            let alternative = format!("e{}", gnu_compiler);
            if Command::new(&alternative).output().is_ok() {
                cfg.compiler(alternative);
            }
        }

        "mips-unknown-linux-musl" => {
            if cfg.get_compiler().path().to_str() == Some("gcc") {
                cfg.compiler("mips-linux-musl-gcc");
            }
        }
        "mipsel-unknown-linux-musl" => {
            if cfg.get_compiler().path().to_str() == Some("gcc") {
                cfg.compiler("mipsel-linux-musl-gcc");
            }
        }

        t if t.contains("musl") => {
            if let Some(root) = build.musl_root(target) {
                let guess = root.join("bin/musl-gcc");
                if guess.exists() {
                    cfg.compiler(guess);
                }
            }
        }

        _ => {}
    }
}

/// The target programming language for a native compiler.
enum Language {
    /// The compiler is targeting C.
    C,
    /// The compiler is targeting C++.
    CPlusPlus,
}

impl Language {
    /// Obtains the name of a compiler in the GCC collection.
    fn gcc(self) -> &'static str {
        match self {
            Language::C => "gcc",
            Language::CPlusPlus => "g++",
        }
    }

    /// Obtains the name of a compiler in the clang suite.
    fn clang(self) -> &'static str {
        match self {
            Language::C => "clang",
            Language::CPlusPlus => "clang++",
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

#[macro_use]
extern crate uucore;
use uucore::utsname::Uname;

static SYNTAX: &'static str = "[OPTION]...";
static SUMMARY: &'static str = "Print certain system information.  With no OPTION, same as -s.";

#[cfg(target_os = "linux")]
static HOST_OS: &'static str = "GNU/Linux";
#[cfg(target_os = "windows")]
static HOST_OS: &'static str = "Windows NT";
#[cfg(target_os = "freebsd")]
static HOST_OS: &'static str = "FreeBSD";
#[cfg(target_os = "openbsd")]
static HOST_OS: &'static str = "OpenBSD";
#[cfg(target_os = "macos")]
static HOST_OS: &'static str = "Darwin";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");

    opts.optflag("a",
                 "all",
                 "Behave as though all of the options -mnrsv were specified.");
    opts.optflag("s", "sysname", "print the operating system name.");
    opts.optflag("n", "nodename", "print the nodename (the nodename may be a name that the system is known by to a communications network).");
    opts.optflag("r", "kernel-release", "print the operating system release.");
    opts.optflag("v", "kernel-version", "print the operating system version.");
    opts.optflag("m", "machine", "print the machine hardware name.");

    // FIXME: Unimplemented
    // opts.optflag("p", "processor", "print the machine processor architecture name.");
    // opts.optflag("i", "hardware-platform", "print the hardware platform.");

    opts.optflag("o", "operating-system", "print the operating system");
    let argc = args.len();
    let matches = opts.parse(args);
    let uname = Uname::new();
    let mut output = String::new();
    if matches.opt_present("sysname") || matches.opt_present("all") || argc == 1 {
        output.push_str(uname.sysname().as_ref());
        output.push_str(" ");
    }

    if matches.opt_present("nodename") || matches.opt_present("all") {
        output.push_str(uname.nodename().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-release") || matches.opt_present("all") {
        output.push_str(uname.release().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-version") || matches.opt_present("all") {
        output.push_str(uname.version().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("machine") || matches.opt_present("all") {
        output.push_str(uname.machine().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("operating-system") || matches.opt_present("all") {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim());

    0
}
<commit_msg>Add Fuchsia as recognized host OS in uname.<commit_after>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

#[macro_use]
extern crate uucore;
use uucore::utsname::Uname;

static SYNTAX: &'static str = "[OPTION]...";
static SUMMARY: &'static str = "Print certain system information.  With no OPTION, same as -s.";

#[cfg(target_os = "linux")]
static HOST_OS: &'static str = "GNU/Linux";
#[cfg(target_os = "windows")]
static HOST_OS: &'static str = "Windows NT";
#[cfg(target_os = "freebsd")]
static HOST_OS: &'static str = "FreeBSD";
#[cfg(target_os = "openbsd")]
static HOST_OS: &'static str = "OpenBSD";
#[cfg(target_os = "macos")]
static HOST_OS: &'static str = "Darwin";
#[cfg(target_os = "fuchsia")]
static HOST_OS: &'static str = "Fuchsia";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");

    opts.optflag("a",
                 "all",
                 "Behave as though all of the options -mnrsv were specified.");
    opts.optflag("s", "sysname", "print the operating system name.");
    opts.optflag("n", "nodename", "print the nodename (the nodename may be a name that the system is known by to a communications network).");
    opts.optflag("r", "kernel-release", "print the operating system release.");
    opts.optflag("v", "kernel-version", "print the operating system version.");
    opts.optflag("m", "machine", "print the machine hardware name.");

    // FIXME: Unimplemented
    // opts.optflag("p", "processor", "print the machine processor architecture name.");
    // opts.optflag("i", "hardware-platform", "print the hardware platform.");

    opts.optflag("o", "operating-system", "print the operating system");
    let argc = args.len();
    let matches = opts.parse(args);
    let uname = Uname::new();
    let mut output = String::new();
    if matches.opt_present("sysname") || matches.opt_present("all") || argc == 1 {
        output.push_str(uname.sysname().as_ref());
        output.push_str(" ");
    }

    if matches.opt_present("nodename") || matches.opt_present("all") {
        output.push_str(uname.nodename().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-release") || matches.opt_present("all") {
        output.push_str(uname.release().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-version") || matches.opt_present("all") {
        output.push_str(uname.version().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("machine") || matches.opt_present("all") {
        output.push_str(uname.machine().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("operating-system") || matches.opt_present("all") {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim());

    0
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use util::graph::{Nodes,Edges};

use core::{
    Dependency,
    PackageId,
    Registry,
    SourceId,
};

use semver;

use util::{CargoResult, Graph, human, internal};

pub struct Resolve {
    graph: Graph<PackageId>
}

impl Resolve {
    fn new() -> Resolve {
        Resolve { graph: Graph::new() }
    }

    pub fn iter<'a>(&'a self) -> Nodes<'a, PackageId> {
        self.graph.iter()
    }

    pub fn deps<'a>(&'a self, pkg: &PackageId) -> Option<Edges<'a, PackageId>> {
        self.graph.edges(pkg)
    }
}

struct Context<'a, R> {
    registry: &'a mut R,
    resolve: Resolve,

    // Eventually, we will have smarter logic for checking for conflicts in the resolve,
    // but without the registry, conflicts should not exist in practice, so this is just
    // a sanity check.
    seen: HashMap<(String, SourceId), semver::Version>
}

impl<'a, R: Registry> Context<'a, R> {
    fn new(registry: &'a mut R) -> Context<'a, R> {
        Context {
            registry: registry,
            resolve: Resolve::new(),
            seen: HashMap::new()
        }
    }
}

pub fn resolve<R: Registry>(root: &PackageId, deps: &[Dependency], registry: &mut R)
                            -> CargoResult<Resolve>
{
    log!(5, "resolve; deps={}", deps);

    let mut context = Context::new(registry);
    try!(resolve_deps(root, deps, &mut context));
    Ok(context.resolve)
}

fn resolve_deps<'a, R: Registry>(parent: &PackageId,
                                 deps: &[Dependency],
                                 ctx: &mut Context<'a, R>)
                                 -> CargoResult<()>
{
    if deps.is_empty() {
        return Ok(());
    }

    for dep in deps.iter() {
        let pkgs = try!(ctx.registry.query(dep));

        if pkgs.is_empty() {
            return Err(human(format!("No package named {} found", dep)));
        }

        if pkgs.len() > 1 {
            return Err(internal(format!("At the moment, Cargo only supports a \
                single source for a particular package name ({}).", dep)));
        }

        let summary = pkgs.get(0).clone();
        let name = summary.get_name().to_str();
        let source_id = summary.get_source_id().clone();
        let version = summary.get_version().clone();

        ctx.resolve.graph.link(parent.clone(), summary.get_package_id().clone());

        let found = {
            let found = ctx.seen.find(&(name.clone(), source_id.clone()));

            if found.is_some() {
                if found == Some(&version) { continue; }
                return Err(human(format!("Cargo found multiple copies of {} in {}. This \
                                        is not currently supported",
                                        summary.get_name(), summary.get_source_id())));
            } else {
                false
            }
        };

        if !found {
            ctx.seen.insert((name, source_id), version);
        }

        ctx.resolve.graph.add(summary.get_package_id().clone(), []);

        let deps: Vec<Dependency> = summary.get_dependencies().iter()
            .filter(|d| d.is_transitive())
            .map(|d| d.clone())
            .collect();

        try!(resolve_deps(summary.get_package_id(), deps.as_slice(), ctx));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use hamcrest::{assert_that, equal_to, contains};

    use core::source::{SourceId, RegistryKind, Location, Remote};
    use core::{Dependency, PackageId, Summary, Registry};
    use util::CargoResult;

    fn resolve<R: Registry>(pkg: &PackageId, deps: &[Dependency], registry: &mut R)
                            -> CargoResult<Vec<PackageId>>
    {
        Ok(try!(super::resolve(pkg, deps, registry)).iter().map(|p| p.clone()).collect())
    }

    trait ToDep {
        fn to_dep(self) -> Dependency;
    }

    impl ToDep for &'static str {
        fn to_dep(self) -> Dependency {
            let url = from_str("http://example.com").unwrap();
            let source_id = SourceId::new(RegistryKind, Remote(url));
            Dependency::parse(self, Some("1.0.0"), &source_id).unwrap()
        }
    }

    impl ToDep for Dependency {
        fn to_dep(self) -> Dependency {
            self
        }
    }

    macro_rules! pkg(
        ($name:expr => $($deps:expr),+) => ({
            let d: Vec<Dependency> = vec!($($deps.to_dep()),+);

            Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
                         d.as_slice())
        });

        ($name:expr) => (
            Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
                         [])
        )
    )

    fn registry_loc() -> SourceId {
        let remote = Location::parse("http://example.com").unwrap();
        SourceId::new(RegistryKind, remote)
    }

    fn pkg(name: &str) -> Summary {
        Summary::new(&pkg_id(name), &[])
    }

    fn pkg_id(name: &str) -> PackageId {
        PackageId::new(name, "1.0.0", &registry_loc()).unwrap()
    }

    fn dep(name: &str) -> Dependency {
        let url = from_str("http://example.com").unwrap();
        let source_id = SourceId::new(RegistryKind, Remote(url));
        Dependency::parse(name, Some("1.0.0"), &source_id).unwrap()
    }

    fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
        pkgs
    }

    fn names(names: &[&'static str]) -> Vec<PackageId> {
        names.iter()
            .map(|name| PackageId::new(*name, "1.0.0", &registry_loc()).unwrap())
            .collect()
    }

    #[test]
    pub fn test_resolving_empty_dependency_list() {
        let res = resolve(&pkg_id("root"), [], &mut registry(vec!())).unwrap();

        assert_that(&res, equal_to(&names([])));
    }

    #[test]
    pub fn test_resolving_only_package() {
        let mut reg = registry(vec!(pkg("foo")));
        let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg);

        assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly());
    }

    #[test]
    pub fn test_resolving_one_dep() {
        let mut reg = registry(vec!(pkg("foo"), pkg("bar")));
        let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg);

        assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly());
    }

    #[test]
    pub fn test_resolving_multiple_deps() {
        let mut reg = registry(vec!(pkg!("foo"), pkg!("bar"), pkg!("baz")));
        let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "baz"])).exactly());
    }

    #[test]
    pub fn test_resolving_transitive_deps() {
        let mut reg = registry(vec!(pkg!("foo"), pkg!("bar" => "foo")));
        let res = resolve(&pkg_id("root"), [dep("bar")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar"])));
    }

    #[test]
    pub fn test_resolving_common_transitive_deps() {
        let mut reg = registry(vec!(pkg!("foo" => "bar"), pkg!("bar")));
        let res = resolve(&pkg_id("root"), [dep("foo"), dep("bar")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar"])));
    }

    #[test]
    pub fn test_resolving_with_dev_deps() {
        let mut reg = registry(vec!(
            pkg!("foo" => "bar", dep("baz").as_dev()),
            pkg!("baz" => "bat", dep("bam").as_dev()),
            pkg!("bar"),
            pkg!("bat")
        ));

        let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz").as_dev()], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar", "baz"])));
    }
}
<commit_msg>Add some unit tests<commit_after>use std::collections::HashMap;
use util::graph::{Nodes,Edges};

use core::{
    Dependency,
    PackageId,
    Registry,
    SourceId,
};

use semver;

use util::{CargoResult, Graph, human, internal};

pub struct Resolve {
    graph: Graph<PackageId>
}

impl Resolve {
    fn new() -> Resolve {
        Resolve { graph: Graph::new() }
    }

    pub fn iter<'a>(&'a self) -> Nodes<'a, PackageId> {
        self.graph.iter()
    }

    pub fn deps<'a>(&'a self, pkg: &PackageId) -> Option<Edges<'a, PackageId>> {
        self.graph.edges(pkg)
    }
}

struct Context<'a, R> {
    registry: &'a mut R,
    resolve: Resolve,

    // Eventually, we will have smarter logic for checking for conflicts in the resolve,
    // but without the registry, conflicts should not exist in practice, so this is just
    // a sanity check.
    seen: HashMap<(String, SourceId), semver::Version>
}

impl<'a, R: Registry> Context<'a, R> {
    fn new(registry: &'a mut R) -> Context<'a, R> {
        Context {
            registry: registry,
            resolve: Resolve::new(),
            seen: HashMap::new()
        }
    }
}

pub fn resolve<R: Registry>(root: &PackageId, deps: &[Dependency], registry: &mut R)
                            -> CargoResult<Resolve>
{
    log!(5, "resolve; deps={}", deps);

    let mut context = Context::new(registry);
    try!(resolve_deps(root, deps, &mut context));
    Ok(context.resolve)
}

fn resolve_deps<'a, R: Registry>(parent: &PackageId,
                                 deps: &[Dependency],
                                 ctx: &mut Context<'a, R>)
                                 -> CargoResult<()>
{
    if deps.is_empty() {
        return Ok(());
    }

    for dep in deps.iter() {
        let pkgs = try!(ctx.registry.query(dep));

        if pkgs.is_empty() {
            return Err(human(format!("No package named {} found", dep)));
        }

        if pkgs.len() > 1 {
            return Err(internal(format!("At the moment, Cargo only supports a \
                single source for a particular package name ({}).", dep)));
        }

        let summary = pkgs.get(0).clone();
        let name = summary.get_name().to_str();
        let source_id = summary.get_source_id().clone();
        let version = summary.get_version().clone();

        ctx.resolve.graph.link(parent.clone(), summary.get_package_id().clone());

        let found = {
            let found = ctx.seen.find(&(name.clone(), source_id.clone()));

            if found.is_some() {
                if found == Some(&version) { continue; }
                return Err(human(format!("Cargo found multiple copies of {} in {}. This \
                                        is not currently supported",
                                        summary.get_name(), summary.get_source_id())));
            } else {
                false
            }
        };

        if !found {
            ctx.seen.insert((name, source_id), version);
        }

        ctx.resolve.graph.add(summary.get_package_id().clone(), []);

        let deps: Vec<Dependency> = summary.get_dependencies().iter()
            .filter(|d| d.is_transitive())
            .map(|d| d.clone())
            .collect();

        try!(resolve_deps(summary.get_package_id(), deps.as_slice(), ctx));
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use hamcrest::{assert_that, equal_to, contains};

    use core::source::{SourceId, RegistryKind, GitKind, Location, Remote};
    use core::{Dependency, PackageId, Summary, Registry};
    use util::CargoResult;

    fn resolve<R: Registry>(pkg: &PackageId, deps: &[Dependency], registry: &mut R)
                            -> CargoResult<Vec<PackageId>>
    {
        Ok(try!(super::resolve(pkg, deps, registry)).iter().map(|p| p.clone()).collect())
    }

    trait ToDep {
        fn to_dep(self) -> Dependency;
    }

    impl ToDep for &'static str {
        fn to_dep(self) -> Dependency {
            let url = from_str("http://example.com").unwrap();
            let source_id = SourceId::new(RegistryKind, Remote(url));
            Dependency::parse(self, Some("1.0.0"), &source_id).unwrap()
        }
    }

    impl ToDep for Dependency {
        fn to_dep(self) -> Dependency {
            self
        }
    }

    macro_rules! pkg(
        ($name:expr => $($deps:expr),+) => ({
            let d: Vec<Dependency> = vec!($($deps.to_dep()),+);

            Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
                         d.as_slice())
        });

        ($name:expr) => (
            Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
                         [])
        )
    )

    fn registry_loc() -> SourceId {
        let remote = Location::parse("http://example.com").unwrap();
        SourceId::new(RegistryKind, remote)
    }

    fn pkg(name: &str) -> Summary {
        Summary::new(&pkg_id(name), &[])
    }

    fn pkg_id(name: &str) -> PackageId {
        PackageId::new(name, "1.0.0", &registry_loc()).unwrap()
    }

    fn pkg_id_loc(name: &str, loc: &str) -> PackageId {
        let remote = Location::parse(loc);
        let source_id = SourceId::new(GitKind("master".to_str()),
                                      remote.unwrap());

        PackageId::new(name, "1.0.0", &source_id).unwrap()
    }

    fn pkg_loc(name: &str, loc: &str) -> Summary {
        Summary::new(&pkg_id_loc(name, loc), &[])
    }

    fn dep(name: &str) -> Dependency {
        let url = from_str("http://example.com").unwrap();
        let source_id = SourceId::new(RegistryKind, Remote(url));
        Dependency::parse(name, Some("1.0.0"), &source_id).unwrap()
    }

    fn dep_loc(name: &str, location: &str) -> Dependency {
        let url = from_str(location).unwrap();
        let source_id = SourceId::new(GitKind("master".to_str()), Remote(url));
        Dependency::parse(name, Some("1.0.0"), &source_id).unwrap()
    }

    fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
        pkgs
    }

    fn names(names: &[&'static str]) -> Vec<PackageId> {
        names.iter()
            .map(|name| PackageId::new(*name, "1.0.0", &registry_loc()).unwrap())
            .collect()
    }

    fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
        names.iter()
            .map(|&(name, loc)| pkg_id_loc(name, loc)).collect()
    }

    #[test]
    pub fn test_resolving_empty_dependency_list() {
        let res = resolve(&pkg_id("root"), [], &mut registry(vec!())).unwrap();

        assert_that(&res, equal_to(&names([])));
    }

    #[test]
    pub fn test_resolving_only_package() {
        let mut reg = registry(vec!(pkg("foo")));
        let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg);

        assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly());
    }

    #[test]
    pub fn test_resolving_one_dep() {
        let mut reg = registry(vec!(pkg("foo"), pkg("bar")));
        let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg);

        assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly());
    }

    #[test]
    pub fn test_resolving_multiple_deps() {
        let mut reg = registry(vec!(pkg!("foo"), pkg!("bar"), pkg!("baz")));
        let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "baz"])).exactly());
    }

    #[test]
    pub fn test_resolving_transitive_deps() {
        let mut reg = registry(vec!(pkg!("foo"), pkg!("bar" => "foo")));
        let res = resolve(&pkg_id("root"), [dep("bar")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar"])));
    }

    #[test]
    pub fn test_resolving_common_transitive_deps() {
        let mut reg = registry(vec!(pkg!("foo" => "bar"), pkg!("bar")));
        let res = resolve(&pkg_id("root"), [dep("foo"), dep("bar")], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar"])));
    }

    #[test]
    pub fn test_resolving_with_same_name() {
        let list = vec!(pkg_loc("foo", "http://first.example.com"),
                        pkg_loc("foo", "http://second.example.com"));

        let mut reg = registry(list);
        let res = resolve(&pkg_id("root"),
                          [dep_loc("foo", "http://first.example.com"),
                           dep_loc("foo", "http://second.example.com")],
                           &mut reg);

        let mut names = loc_names([("foo", "http://first.example.com"),
                              ("foo", "http://second.example.com")]);

        names.push(pkg_id("root"));

        assert_that(&res.unwrap(), contains(names).exactly());
    }

    #[test]
    pub fn test_resolving_with_dev_deps() {
        let mut reg = registry(vec!(
            pkg!("foo" => "bar", dep("baz").as_dev()),
            pkg!("baz" => "bat", dep("bam").as_dev()),
            pkg!("bar"),
            pkg!("bat")
        ));

        let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz").as_dev()], &mut reg).unwrap();

        assert_that(&res, contains(names(["root", "foo", "bar", "baz"])));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::path::MAIN_SEPARATOR;

/// Removes the parent component of the path
pub fn basename(path: &str) -> &str {
    let mut index = 0;
    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            index = id;
        }
    }

    // FIXME: On Windows, should return what for C:file.txt D:file.txt and \\server\share ?
    if index != 0 {
        return &path[index + 1..];
    }

    path
}

/// Removes the extension from the path
pub fn remove_extension(path: &str) -> &str {
    let mut has_dir = false;
    let mut dir_index = 0;
    let mut ext_index = 0;

    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            has_dir = true;
            dir_index = id;
        }
        if character == '.' {
            ext_index = id;
        }
    }

    // Account for hidden files and directories
    if ext_index != 0 && (!has_dir || dir_index + 2 <= ext_index) {
        return &path[0..ext_index];
    }

    path
}

/// Removes the basename from the path.
pub fn dirname(path: &str) -> &str {
    let mut has_dir = false;
    let mut index = 0;
    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            has_dir = true;
            index = id;
        }
    }

    // FIXME: On Windows, return what for C:file.txt D:file.txt and \\server\share ?
    if !has_dir {
        "."
    } else if index == 0 {
        &path[..1]
    } else {
        &path[0..index]
    }
}

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

    fn correct(input: &str) -> String {
        input.replace('/', &MAIN_SEPARATOR.to_string())
    }

    #[test]
    fn path_remove_ext_simple() {
        assert_eq!(remove_extension("foo.txt"), "foo");
    }

    #[test]
    fn path_remove_ext_dir() {
        assert_eq!(
            remove_extension(&correct("dir/foo.txt")),
            correct("dir/foo")
        );
    }

    #[test]
    fn path_hidden() {
        assert_eq!(remove_extension(".foo"), ".foo")
    }

    #[test]
    fn path_remove_ext_utf8() {
        assert_eq!(remove_extension("💖.txt"), "💖");
    }

    #[test]
    fn path_remove_ext_empty() {
        assert_eq!(remove_extension(""), "");
    }

    #[test]
    fn path_basename_simple() {
        assert_eq!(basename("foo.txt"), "foo.txt");
    }

    #[test]
    fn path_basename_no_ext() {
        assert_eq!(remove_extension(basename("foo.txt")), "foo");
    }

    #[test]
    fn path_basename_dir() {
        assert_eq!(basename(&correct("dir/foo.txt")), "foo.txt");
    }

    #[test]
    fn path_basename_empty() {
        assert_eq!(basename(""), "");
    }

    #[test]
    fn path_basename_utf8() {
        assert_eq!(basename(&correct("💖/foo.txt")), "foo.txt");
        assert_eq!(basename(&correct("dir/💖.txt")), "💖.txt");
    }

    #[test]
    fn path_dirname_simple() {
        assert_eq!(dirname("foo.txt"), ".");
    }

    #[test]
    fn path_dirname_dir() {
        assert_eq!(dirname(&correct("dir/foo.txt")), "dir");
    }

    #[test]
    fn path_dirname_utf8() {
        assert_eq!(dirname(&correct("💖/foo.txt")), "💖");
        assert_eq!(dirname(&correct("dir/💖.txt")), "dir");
    }

    #[test]
    fn path_dirname_empty() {
        assert_eq!(dirname(""), ".");
    }

    #[test]
    fn path_dirname_root() {
        #[cfg(windows)]
        assert_eq!(dirname("C:\\"), "C:");
        #[cfg(windows)]
        assert_eq!(dirname("\\"), "\\");
        #[cfg(not(windows))]
        assert_eq!(dirname("/"), "/");
    }
}
<commit_msg>macronize repetitive tests in exec/input<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::path::MAIN_SEPARATOR;

/// Removes the parent component of the path
pub fn basename(path: &str) -> &str {
    let mut index = 0;
    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            index = id;
        }
    }

    // FIXME: On Windows, should return what for C:file.txt D:file.txt and \\server\share ?
    if index != 0 {
        return &path[index + 1..];
    }

    path
}

/// Removes the extension from the path
pub fn remove_extension(path: &str) -> &str {
    let mut has_dir = false;
    let mut dir_index = 0;
    let mut ext_index = 0;

    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            has_dir = true;
            dir_index = id;
        }
        if character == '.' {
            ext_index = id;
        }
    }

    // Account for hidden files and directories
    if ext_index != 0 && (!has_dir || dir_index + 2 <= ext_index) {
        return &path[0..ext_index];
    }

    path
}

/// Removes the basename from the path.
pub fn dirname(path: &str) -> &str {
    let mut has_dir = false;
    let mut index = 0;
    for (id, character) in path.char_indices() {
        if character == MAIN_SEPARATOR {
            has_dir = true;
            index = id;
        }
    }

    // FIXME: On Windows, return what for C:file.txt D:file.txt and \\server\share ?
    if !has_dir {
        "."
    } else if index == 0 {
        &path[..1]
    } else {
        &path[0..index]
    }
}

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

    fn correct(input: &str) -> String {
        input.replace('/', &MAIN_SEPARATOR.to_string())
    }

    macro_rules! func_tests {
        ($($name:ident: $func:ident for $input:expr => $output:expr)+) => {
            $(
                #[test]
                fn $name() {
                    assert_eq!($func(&correct($input)), correct($output));
                }
            )+
        }
    }

    func_tests! {
        remove_ext_simple:  remove_extension  for  "foo.txt"      =>  "foo"
        remove_ext_dir:     remove_extension  for  "dir/foo.txt"  =>  "dir/foo"
        hidden:             remove_extension  for  ".foo"         =>  ".foo"
        remove_ext_utf8:    remove_extension  for  "💖.txt"       =>  "💖"
        remove_ext_empty:   remove_extension  for  ""             =>  ""

        basename_simple:  basename  for  "foo.txt"      =>  "foo.txt"
        basename_dir:     basename  for  "dir/foo.txt"  =>  "foo.txt"
        basename_empty:   basename  for  ""             =>  ""
        basename_utf8_0:  basename  for  "💖/foo.txt"   =>  "foo.txt"
        basename_utf8_1:  basename  for  "dir/💖.txt"   =>  "💖.txt"

        dirname_simple:  dirname  for  "foo.txt"      =>  "."
        dirname_dir:     dirname  for  "dir/foo.txt"  =>  "dir"
        dirname_utf8_0:  dirname  for  "💖/foo.txt"   =>  "💖"
        dirname_utf8_1:  dirname  for  "dir/💖.txt"   =>  "dir"
        dirname_empty:   dirname  for  ""             =>  "."
    }

    #[test]
    fn dirname_root() {
        #[cfg(windows)]
        assert_eq!(dirname("C:\\"), "C:");
        #[cfg(windows)]
        assert_eq!(dirname("\\"), "\\");
        #[cfg(not(windows))]
        assert_eq!(dirname("/"), "/");
    }
}
<|endoftext|>


<commit_before>use float::Float;
use int::{Int, CastInto};

macro_rules! int_to_float {
    ($i:expr, $ity:ty, $fty:ty) => ({
        let i = $i;
        if i == 0 {
            return 0.0
        }

        let mant_dig = <$fty>::SIGNIFICAND_BITS + 1;
        let exponent_bias = <$fty>::EXPONENT_BIAS;

        let n = <$ity>::BITS;
        let (s, a) = i.extract_sign();
        let mut a = a;

        // number of significant digits
        let sd = n - a.leading_zeros();

        // exponent
        let mut e = sd - 1;

        if <$ity>::BITS < mant_dig {
            return <$fty>::from_parts(s,
                (e + exponent_bias) as <$fty as Float>::Int,
                (a as <$fty as Float>::Int) << (mant_dig - e - 1))
        }

        a = if sd > mant_dig {
            /* start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
            *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
            *                                                12345678901234567890123456
            *  1 = msb 1 bit
            *  P = bit MANT_DIG-1 bits to the right of 1
            *  Q = bit MANT_DIG bits to the right of 1
            *  R = "or" of all bits to the right of Q
            */
            let mant_dig_plus_one = mant_dig + 1;
            let mant_dig_plus_two = mant_dig + 2;
            a = if sd == mant_dig_plus_one {
                a << 1
            } else if sd == mant_dig_plus_two {
                a
            } else {
                (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
                ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
            };

            /* finish: */
            a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
            a += 1; /* round - this step may add a significant bit */
            a >>= 2; /* dump Q and R */

            /* a is now rounded to mant_dig or mant_dig+1 bits */
            if (a & (1 << mant_dig)) != 0 {
                a >>= 1; e += 1;
            }
            a
            /* a is now rounded to mant_dig bits */
        } else {
            a.wrapping_shl(mant_dig - sd)
            /* a is now rounded to mant_dig bits */
        };

        <$fty>::from_parts(s,
            (e + exponent_bias) as <$fty as Float>::Int,
            a as <$fty as Float>::Int)
    })
}

intrinsics! {
    #[arm_aeabi_alias = __aeabi_i2f]
    pub extern "C" fn __floatsisf(i: i32) -> f32 {
        int_to_float!(i, i32, f32)
    }

    #[arm_aeabi_alias = __aeabi_i2d]
    pub extern "C" fn __floatsidf(i: i32) -> f64 {
        int_to_float!(i, i32, f64)
    }

    #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))]
    #[arm_aeabi_alias = __aeabi_l2d]
    pub extern "C" fn __floatdidf(i: i64) -> f64 {
        // On x86_64 LLVM will use native instructions for this conversion, we
        // can just do it directly
        if cfg!(target_arch = "x86_64") {
            i as f64
        } else {
            int_to_float!(i, i64, f64)
        }
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floattisf(i: i128) -> f32 {
        int_to_float!(i, i128, f32)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floattidf(i: i128) -> f64 {
        int_to_float!(i, i128, f64)
    }

    #[arm_aeabi_alias = __aeabi_ui2f]
    pub extern "C" fn __floatunsisf(i: u32) -> f32 {
        int_to_float!(i, u32, f32)
    }

    #[arm_aeabi_alias = __aeabi_ui2d]
    pub extern "C" fn __floatunsidf(i: u32) -> f64 {
        int_to_float!(i, u32, f64)
    }

    #[use_c_shim_if(all(not(target_env = "msvc"),
                        any(target_arch = "x86",
                            all(not(windows), target_arch = "x86_64"))))]
    #[arm_aeabi_alias = __aeabi_ul2d]
    pub extern "C" fn __floatundidf(i: u64) -> f64 {
        int_to_float!(i, u64, f64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floatuntisf(i: u128) -> f32 {
        int_to_float!(i, u128, f32)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floatuntidf(i: u128) -> f64 {
        int_to_float!(i, u128, f64)
    }
}

#[derive(PartialEq)]
enum Sign {
    Positive,
    Negative
}

fn float_to_int<F: Float, I: Int>(f: F) -> I where
    F::Int: CastInto<u32>,
    F::Int: CastInto<I>,
{
    let f = f;
    let fixint_min = I::min_value();
    let fixint_max = I::max_value();
    let fixint_bits = I::BITS;
    let fixint_unsigned = fixint_min == I::ZERO;

    let sign_bit = F::SIGN_MASK;
    let significand_bits = F::SIGNIFICAND_BITS;
    let exponent_bias = F::EXPONENT_BIAS;
    //let exponent_max = F::exponent_max() as usize;

    // Break a into sign, exponent, significand
    let a_rep = F::repr(f);
    let a_abs = a_rep & !sign_bit;

    // this is used to work around -1 not being available for unsigned
    let sign = if (a_rep & sign_bit) == F::Int::ZERO { Sign::Positive } else { Sign::Negative };
    let mut exponent: u32 = (a_abs >> significand_bits).cast();
    let significand = (a_abs & F::SIGNIFICAND_MASK) | F::IMPLICIT_BIT;

    // if < 1 or unsigned & negative
    if exponent < exponent_bias ||
        fixint_unsigned && sign == Sign::Negative {
        return I::ZERO;
    }
    exponent -= exponent_bias;

    // If the value is infinity, saturate.
    // If the value is too large for the integer type, 0.
    if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
        return if sign == Sign::Positive {fixint_max} else {fixint_min}
    }
    // If 0 <= exponent < significand_bits, right shift to get the result.
    // Otherwise, shift left.
    // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
    let r: I = if exponent < significand_bits {
        (significand >> (significand_bits - exponent)).cast()
    } else {
        (significand << (exponent - significand_bits)).cast()
    };

    if sign == Sign::Negative {
        (!r).wrapping_add(I::ONE)
    } else {
        r
    }
}

intrinsics! {
    #[arm_aeabi_alias = __aeabi_f2iz]
    pub extern "C" fn __fixsfsi(f: f32) -> i32 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_f2lz]
    pub extern "C" fn __fixsfdi(f: f32) -> i64 {
        float_to_int(f)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixsfti(f: f32) -> i128 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_d2iz]
    pub extern "C" fn __fixdfsi(f: f64) -> i32 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_d2lz]
    pub extern "C" fn __fixdfdi(f: f64) -> i64 {
        float_to_int(f)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixdfti(f: f64) -> i128 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_f2uiz]
    pub extern "C" fn __fixunssfsi(f: f32) -> u32 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_f2ulz]
    pub extern "C" fn __fixunssfdi(f: f32) -> u64 {
        float_to_int(f)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixunssfti(f: f32) -> u128 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_d2uiz]
    pub extern "C" fn __fixunsdfsi(f: f64) -> u32 {
        float_to_int(f)
    }

    #[arm_aeabi_alias = __aeabi_d2ulz]
    pub extern "C" fn __fixunsdfdi(f: f64) -> u64 {
        float_to_int(f)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixunsdfti(f: f64) -> u128 {
        float_to_int(f)
    }
}
<commit_msg>Partially revert a272d753f5c75ab9acb7b282765a3c7517caac25<commit_after>use float::Float;
use int::Int;

macro_rules! int_to_float {
    ($i:expr, $ity:ty, $fty:ty) => ({
        let i = $i;
        if i == 0 {
            return 0.0
        }

        let mant_dig = <$fty>::SIGNIFICAND_BITS + 1;
        let exponent_bias = <$fty>::EXPONENT_BIAS;

        let n = <$ity>::BITS;
        let (s, a) = i.extract_sign();
        let mut a = a;

        // number of significant digits
        let sd = n - a.leading_zeros();

        // exponent
        let mut e = sd - 1;

        if <$ity>::BITS < mant_dig {
            return <$fty>::from_parts(s,
                (e + exponent_bias) as <$fty as Float>::Int,
                (a as <$fty as Float>::Int) << (mant_dig - e - 1))
        }

        a = if sd > mant_dig {
            /* start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
            *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
            *                                                12345678901234567890123456
            *  1 = msb 1 bit
            *  P = bit MANT_DIG-1 bits to the right of 1
            *  Q = bit MANT_DIG bits to the right of 1
            *  R = "or" of all bits to the right of Q
            */
            let mant_dig_plus_one = mant_dig + 1;
            let mant_dig_plus_two = mant_dig + 2;
            a = if sd == mant_dig_plus_one {
                a << 1
            } else if sd == mant_dig_plus_two {
                a
            } else {
                (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
                ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
            };

            /* finish: */
            a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
            a += 1; /* round - this step may add a significant bit */
            a >>= 2; /* dump Q and R */

            /* a is now rounded to mant_dig or mant_dig+1 bits */
            if (a & (1 << mant_dig)) != 0 {
                a >>= 1; e += 1;
            }
            a
            /* a is now rounded to mant_dig bits */
        } else {
            a.wrapping_shl(mant_dig - sd)
            /* a is now rounded to mant_dig bits */
        };

        <$fty>::from_parts(s,
            (e + exponent_bias) as <$fty as Float>::Int,
            a as <$fty as Float>::Int)
    })
}

intrinsics! {
    #[arm_aeabi_alias = __aeabi_i2f]
    pub extern "C" fn __floatsisf(i: i32) -> f32 {
        int_to_float!(i, i32, f32)
    }

    #[arm_aeabi_alias = __aeabi_i2d]
    pub extern "C" fn __floatsidf(i: i32) -> f64 {
        int_to_float!(i, i32, f64)
    }

    #[use_c_shim_if(all(target_arch = "x86", not(target_env = "msvc")))]
    #[arm_aeabi_alias = __aeabi_l2d]
    pub extern "C" fn __floatdidf(i: i64) -> f64 {
        // On x86_64 LLVM will use native instructions for this conversion, we
        // can just do it directly
        if cfg!(target_arch = "x86_64") {
            i as f64
        } else {
            int_to_float!(i, i64, f64)
        }
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floattisf(i: i128) -> f32 {
        int_to_float!(i, i128, f32)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floattidf(i: i128) -> f64 {
        int_to_float!(i, i128, f64)
    }

    #[arm_aeabi_alias = __aeabi_ui2f]
    pub extern "C" fn __floatunsisf(i: u32) -> f32 {
        int_to_float!(i, u32, f32)
    }

    #[arm_aeabi_alias = __aeabi_ui2d]
    pub extern "C" fn __floatunsidf(i: u32) -> f64 {
        int_to_float!(i, u32, f64)
    }

    #[use_c_shim_if(all(not(target_env = "msvc"),
                        any(target_arch = "x86",
                            all(not(windows), target_arch = "x86_64"))))]
    #[arm_aeabi_alias = __aeabi_ul2d]
    pub extern "C" fn __floatundidf(i: u64) -> f64 {
        int_to_float!(i, u64, f64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floatuntisf(i: u128) -> f32 {
        int_to_float!(i, u128, f32)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __floatuntidf(i: u128) -> f64 {
        int_to_float!(i, u128, f64)
    }
}

#[derive(PartialEq)]
enum Sign {
    Positive,
    Negative
}

macro_rules! float_to_int {
    ($f:expr, $fty:ty, $ity:ty) => ({
        let f = $f;
        let fixint_min = <$ity>::min_value();
        let fixint_max = <$ity>::max_value();
        let fixint_bits = <$ity>::BITS as usize;
        let fixint_unsigned = fixint_min == 0;

        let sign_bit = <$fty>::SIGN_MASK;
        let significand_bits = <$fty>::SIGNIFICAND_BITS as usize;
        let exponent_bias = <$fty>::EXPONENT_BIAS as usize;
        //let exponent_max = <$fty>::exponent_max() as usize;

        // Break a into sign, exponent, significand
        let a_rep = <$fty>::repr(f);
        let a_abs = a_rep & !sign_bit;

        // this is used to work around -1 not being available for unsigned
        let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
        let mut exponent = (a_abs >> significand_bits) as usize;
        let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT;

        // if < 1 or unsigned & negative
        if  exponent < exponent_bias ||
            fixint_unsigned && sign == Sign::Negative {
            return 0
        }
        exponent -= exponent_bias;

        // If the value is infinity, saturate.
        // If the value is too large for the integer type, 0.
        if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
            return if sign == Sign::Positive {fixint_max} else {fixint_min}
        }
        // If 0 <= exponent < significand_bits, right shift to get the result.
        // Otherwise, shift left.
        // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
        let r = if exponent < significand_bits {
            (significand >> (significand_bits - exponent)) as $ity
        } else {
            (significand as $ity) << (exponent - significand_bits)
        };

        if sign == Sign::Negative {
            (!r).wrapping_add(1)
        } else {
            r
        }
    })
}

intrinsics! {
    #[arm_aeabi_alias = __aeabi_f2iz]
    pub extern "C" fn __fixsfsi(f: f32) -> i32 {
        float_to_int!(f, f32, i32)
    }

    #[arm_aeabi_alias = __aeabi_f2lz]
    pub extern "C" fn __fixsfdi(f: f32) -> i64 {
        float_to_int!(f, f32, i64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixsfti(f: f32) -> i128 {
        float_to_int!(f, f32, i128)
    }

    #[arm_aeabi_alias = __aeabi_d2iz]
    pub extern "C" fn __fixdfsi(f: f64) -> i32 {
        float_to_int!(f, f64, i32)
    }

    #[arm_aeabi_alias = __aeabi_d2lz]
    pub extern "C" fn __fixdfdi(f: f64) -> i64 {
        float_to_int!(f, f64, i64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixdfti(f: f64) -> i128 {
        float_to_int!(f, f64, i128)
    }

    #[arm_aeabi_alias = __aeabi_f2uiz]
    pub extern "C" fn __fixunssfsi(f: f32) -> u32 {
        float_to_int!(f, f32, u32)
    }

    #[arm_aeabi_alias = __aeabi_f2ulz]
    pub extern "C" fn __fixunssfdi(f: f32) -> u64 {
        float_to_int!(f, f32, u64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixunssfti(f: f32) -> u128 {
        float_to_int!(f, f32, u128)
    }

    #[arm_aeabi_alias = __aeabi_d2uiz]
    pub extern "C" fn __fixunsdfsi(f: f64) -> u32 {
        float_to_int!(f, f64, u32)
    }

    #[arm_aeabi_alias = __aeabi_d2ulz]
    pub extern "C" fn __fixunsdfdi(f: f64) -> u64 {
        float_to_int!(f, f64, u64)
    }

    #[unadjusted_on_win64]
    pub extern "C" fn __fixunsdfti(f: f64) -> u128 {
        float_to_int!(f, f64, u128)
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add all the dervived traits Sample needs<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, BitAnd, BitOr, Mul, Sub, Shl, Shr};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + BitAnd<Self, Output = Self> +
                  BitOr<Self, Output = Self> + Mul<Output = Self> +
                  Shl<u32, Output = Self> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>//! Code related to parsing literals.

use crate::ast::{self, Lit, LitKind};
use crate::token::{self, Token};

use rustc_lexer::unescape::{unescape_byte, unescape_char};
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;

use std::ascii;
use tracing::debug;

pub enum LitError {
    NotLiteral,
    LexerError,
    InvalidSuffix,
    InvalidIntSuffix,
    InvalidFloatSuffix,
    NonDecimalFloat(u32),
    IntTooLarge,
}

impl LitKind {
    /// Converts literal token into a semantic literal.
    fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
        let token::Lit { kind, symbol, suffix } = lit;
        if suffix.is_some() && !kind.may_have_suffix() {
            return Err(LitError::InvalidSuffix);
        }

        Ok(match kind {
            token::Bool => {
                assert!(symbol.is_bool_lit());
                LitKind::Bool(symbol == kw::True)
            }
            token::Byte => {
                return unescape_byte(&symbol.as_str())
                    .map(LitKind::Byte)
                    .map_err(|_| LitError::LexerError);
            }
            token::Char => {
                return unescape_char(&symbol.as_str())
                    .map(LitKind::Char)
                    .map_err(|_| LitError::LexerError);
            }

            // There are some valid suffixes for integer and float literals,
            // so all the handling is done internally.
            token::Integer => return integer_lit(symbol, suffix),
            token::Float => return float_lit(symbol, suffix),

            token::Str => {
                // If there are no characters requiring special treatment we can
                // reuse the symbol from the token. Otherwise, we must generate a
                // new symbol because the string in the LitKind is different to the
                // string in the token.
                let s = symbol.as_str();
                let symbol =
                    if s.contains(&['\\', '\r'][..]) {
                        let mut buf = String::with_capacity(s.len());
                        let mut error = Ok(());
                        unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
                            match unescaped_char {
                                Ok(c) => buf.push(c),
                                Err(_) => error = Err(LitError::LexerError),
                            }
                        });
                        error?;
                        Symbol::intern(&buf)
                    } else {
                        symbol
                    };
                LitKind::Str(symbol, ast::StrStyle::Cooked)
            }
            token::StrRaw(n) => {
                // Ditto.
                let s = symbol.as_str();
                let symbol =
                    if s.contains('\r') {
                        let mut buf = String::with_capacity(s.len());
                        let mut error = Ok(());
                        unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
                            match unescaped_char {
                                Ok(c) => buf.push(c),
                                Err(_) => error = Err(LitError::LexerError),
                            }
                        });
                        error?;
                        buf.shrink_to_fit();
                        Symbol::intern(&buf)
                    } else {
                        symbol
                    };
                LitKind::Str(symbol, ast::StrStyle::Raw(n))
            }
            token::ByteStr => {
                let s = symbol.as_str();
                let mut buf = Vec::with_capacity(s.len());
                let mut error = Ok(());
                unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
                    match unescaped_byte {
                        Ok(c) => buf.push(c),
                        Err(_) => error = Err(LitError::LexerError),
                    }
                });
                error?;
                buf.shrink_to_fit();
                LitKind::ByteStr(buf.into())
            }
            token::ByteStrRaw(_) => {
                let s = symbol.as_str();
                let bytes = if s.contains('\r') {
                    let mut buf = Vec::with_capacity(s.len());
                    let mut error = Ok(());
                    unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
                        match unescaped_byte {
                            Ok(c) => buf.push(c),
                            Err(_) => error = Err(LitError::LexerError),
                        }
                    });
                    error?;
                    buf.shrink_to_fit();
                    buf
                } else {
                    symbol.to_string().into_bytes()
                };

                LitKind::ByteStr(bytes.into())
            }
            token::Err => LitKind::Err(symbol),
        })
    }

    /// Attempts to recover a token from semantic literal.
    /// This function is used when the original token doesn't exist (e.g. the literal is created
    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
    pub fn to_lit_token(&self) -> token::Lit {
        let (kind, symbol, suffix) = match *self {
            LitKind::Str(symbol, ast::StrStyle::Cooked) => {
                // Don't re-intern unless the escaped string is different.
                let s = symbol.as_str();
                let escaped = s.escape_default().to_string();
                let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) };
                (token::Str, symbol, None)
            }
            LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None),
            LitKind::ByteStr(ref bytes) => {
                let string = bytes
                    .iter()
                    .cloned()
                    .flat_map(ascii::escape_default)
                    .map(Into::<char>::into)
                    .collect::<String>();
                (token::ByteStr, Symbol::intern(&string), None)
            }
            LitKind::Byte(byte) => {
                let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
                (token::Byte, Symbol::intern(&string), None)
            }
            LitKind::Char(ch) => {
                let string: String = ch.escape_default().map(Into::<char>::into).collect();
                (token::Char, Symbol::intern(&string), None)
            }
            LitKind::Int(n, ty) => {
                let suffix = match ty {
                    ast::LitIntType::Unsigned(ty) => Some(ty.name()),
                    ast::LitIntType::Signed(ty) => Some(ty.name()),
                    ast::LitIntType::Unsuffixed => None,
                };
                (token::Integer, sym::integer(n), suffix)
            }
            LitKind::Float(symbol, ty) => {
                let suffix = match ty {
                    ast::LitFloatType::Suffixed(ty) => Some(ty.name()),
                    ast::LitFloatType::Unsuffixed => None,
                };
                (token::Float, symbol, suffix)
            }
            LitKind::Bool(value) => {
                let symbol = if value { kw::True } else { kw::False };
                (token::Bool, symbol, None)
            }
            LitKind::Err(symbol) => (token::Err, symbol, None),
        };

        token::Lit::new(kind, symbol, suffix)
    }
}

impl Lit {
    /// Converts literal token into an AST literal.
    pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
        Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
    }

    /// Converts arbitrary token into an AST literal.
    ///
    /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
    pub fn from_token(token: &Token) -> Result<Lit, LitError> {
        let lit = match token.uninterpolate().kind {
            token::Ident(name, false) if name.is_bool_lit() => {
                token::Lit::new(token::Bool, name, None)
            }
            token::Literal(lit) => lit,
            token::Interpolated(ref nt) => {
                if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
                    if let ast::ExprKind::Lit(lit) = &expr.kind {
                        return Ok(lit.clone());
                    }
                }
                return Err(LitError::NotLiteral);
            }
            _ => return Err(LitError::NotLiteral),
        };

        Lit::from_lit_token(lit, token.span)
    }

    /// Attempts to recover an AST literal from semantic literal.
    /// This function is used when the original token doesn't exist (e.g. the literal is created
    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
    pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
        Lit { token: kind.to_lit_token(), kind, span }
    }

    /// Losslessly convert an AST literal into a token.
    pub fn to_token(&self) -> Token {
        let kind = match self.token.kind {
            token::Bool => token::Ident(self.token.symbol, false),
            _ => token::Literal(self.token),
        };
        Token::new(kind, self.span)
    }
}

fn strip_underscores(symbol: Symbol) -> Symbol {
    // Do not allocate a new string unless necessary.
    let s = symbol.as_str();
    if s.contains('_') {
        let mut s = s.to_string();
        s.retain(|c| c != '_');
        return Symbol::intern(&s);
    }
    symbol
}

fn filtered_float_lit(
    symbol: Symbol,
    suffix: Option<Symbol>,
    base: u32,
) -> Result<LitKind, LitError> {
    debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base);
    if base != 10 {
        return Err(LitError::NonDecimalFloat(base));
    }
    Ok(match suffix {
        Some(suf) => LitKind::Float(
            symbol,
            ast::LitFloatType::Suffixed(match suf {
                sym::f32 => ast::FloatTy::F32,
                sym::f64 => ast::FloatTy::F64,
                _ => return Err(LitError::InvalidFloatSuffix),
            }),
        ),
        None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed),
    })
}

fn float_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
    debug!("float_lit: {:?}, {:?}", symbol, suffix);
    filtered_float_lit(strip_underscores(symbol), suffix, 10)
}

fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
    debug!("integer_lit: {:?}, {:?}", symbol, suffix);
    let symbol = strip_underscores(symbol);
    let s = symbol.as_str();

    let base = match s.as_bytes() {
        [b'0', b'x', ..] => 16,
        [b'0', b'o', ..] => 8,
        [b'0', b'b', ..] => 2,
        _ => 10,
    };

    let ty = match suffix {
        Some(suf) => match suf {
            sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize),
            sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8),
            sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16),
            sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32),
            sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64),
            sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128),
            sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize),
            sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8),
            sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16),
            sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32),
            sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64),
            sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128),
            // `1f64` and `2f32` etc. are valid float literals, and
            // `fxxx` looks more like an invalid float literal than invalid integer literal.
            _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
            _ => return Err(LitError::InvalidIntSuffix),
        },
        _ => ast::LitIntType::Unsuffixed,
    };

    let s = &s[if base != 10 { 2 } else { 0 }..];
    u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| {
        // Small bases are lexed as if they were base 10, e.g, the string
        // might be `0b10201`. This will cause the conversion above to fail,
        // but these kinds of errors are already reported by the lexer.
        let from_lexer =
            base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
        if from_lexer { LitError::LexerError } else { LitError::IntTooLarge }
    })
}
<commit_msg>Auto merge of #81077 - bugadani:shrink, r=Mark-Simulacrum<commit_after>//! Code related to parsing literals.

use crate::ast::{self, Lit, LitKind};
use crate::token::{self, Token};

use rustc_lexer::unescape::{unescape_byte, unescape_char};
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;

use std::ascii;
use tracing::debug;

pub enum LitError {
    NotLiteral,
    LexerError,
    InvalidSuffix,
    InvalidIntSuffix,
    InvalidFloatSuffix,
    NonDecimalFloat(u32),
    IntTooLarge,
}

impl LitKind {
    /// Converts literal token into a semantic literal.
    fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
        let token::Lit { kind, symbol, suffix } = lit;
        if suffix.is_some() && !kind.may_have_suffix() {
            return Err(LitError::InvalidSuffix);
        }

        Ok(match kind {
            token::Bool => {
                assert!(symbol.is_bool_lit());
                LitKind::Bool(symbol == kw::True)
            }
            token::Byte => {
                return unescape_byte(&symbol.as_str())
                    .map(LitKind::Byte)
                    .map_err(|_| LitError::LexerError);
            }
            token::Char => {
                return unescape_char(&symbol.as_str())
                    .map(LitKind::Char)
                    .map_err(|_| LitError::LexerError);
            }

            // There are some valid suffixes for integer and float literals,
            // so all the handling is done internally.
            token::Integer => return integer_lit(symbol, suffix),
            token::Float => return float_lit(symbol, suffix),

            token::Str => {
                // If there are no characters requiring special treatment we can
                // reuse the symbol from the token. Otherwise, we must generate a
                // new symbol because the string in the LitKind is different to the
                // string in the token.
                let s = symbol.as_str();
                let symbol =
                    if s.contains(&['\\', '\r'][..]) {
                        let mut buf = String::with_capacity(s.len());
                        let mut error = Ok(());
                        unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
                            match unescaped_char {
                                Ok(c) => buf.push(c),
                                Err(_) => error = Err(LitError::LexerError),
                            }
                        });
                        error?;
                        Symbol::intern(&buf)
                    } else {
                        symbol
                    };
                LitKind::Str(symbol, ast::StrStyle::Cooked)
            }
            token::StrRaw(n) => {
                // Ditto.
                let s = symbol.as_str();
                let symbol =
                    if s.contains('\r') {
                        let mut buf = String::with_capacity(s.len());
                        let mut error = Ok(());
                        unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
                            match unescaped_char {
                                Ok(c) => buf.push(c),
                                Err(_) => error = Err(LitError::LexerError),
                            }
                        });
                        error?;
                        Symbol::intern(&buf)
                    } else {
                        symbol
                    };
                LitKind::Str(symbol, ast::StrStyle::Raw(n))
            }
            token::ByteStr => {
                let s = symbol.as_str();
                let mut buf = Vec::with_capacity(s.len());
                let mut error = Ok(());
                unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
                    match unescaped_byte {
                        Ok(c) => buf.push(c),
                        Err(_) => error = Err(LitError::LexerError),
                    }
                });
                error?;
                LitKind::ByteStr(buf.into())
            }
            token::ByteStrRaw(_) => {
                let s = symbol.as_str();
                let bytes = if s.contains('\r') {
                    let mut buf = Vec::with_capacity(s.len());
                    let mut error = Ok(());
                    unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
                        match unescaped_byte {
                            Ok(c) => buf.push(c),
                            Err(_) => error = Err(LitError::LexerError),
                        }
                    });
                    error?;
                    buf
                } else {
                    symbol.to_string().into_bytes()
                };

                LitKind::ByteStr(bytes.into())
            }
            token::Err => LitKind::Err(symbol),
        })
    }

    /// Attempts to recover a token from semantic literal.
    /// This function is used when the original token doesn't exist (e.g. the literal is created
    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
    pub fn to_lit_token(&self) -> token::Lit {
        let (kind, symbol, suffix) = match *self {
            LitKind::Str(symbol, ast::StrStyle::Cooked) => {
                // Don't re-intern unless the escaped string is different.
                let s = symbol.as_str();
                let escaped = s.escape_default().to_string();
                let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) };
                (token::Str, symbol, None)
            }
            LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None),
            LitKind::ByteStr(ref bytes) => {
                let string = bytes
                    .iter()
                    .cloned()
                    .flat_map(ascii::escape_default)
                    .map(Into::<char>::into)
                    .collect::<String>();
                (token::ByteStr, Symbol::intern(&string), None)
            }
            LitKind::Byte(byte) => {
                let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
                (token::Byte, Symbol::intern(&string), None)
            }
            LitKind::Char(ch) => {
                let string: String = ch.escape_default().map(Into::<char>::into).collect();
                (token::Char, Symbol::intern(&string), None)
            }
            LitKind::Int(n, ty) => {
                let suffix = match ty {
                    ast::LitIntType::Unsigned(ty) => Some(ty.name()),
                    ast::LitIntType::Signed(ty) => Some(ty.name()),
                    ast::LitIntType::Unsuffixed => None,
                };
                (token::Integer, sym::integer(n), suffix)
            }
            LitKind::Float(symbol, ty) => {
                let suffix = match ty {
                    ast::LitFloatType::Suffixed(ty) => Some(ty.name()),
                    ast::LitFloatType::Unsuffixed => None,
                };
                (token::Float, symbol, suffix)
            }
            LitKind::Bool(value) => {
                let symbol = if value { kw::True } else { kw::False };
                (token::Bool, symbol, None)
            }
            LitKind::Err(symbol) => (token::Err, symbol, None),
        };

        token::Lit::new(kind, symbol, suffix)
    }
}

impl Lit {
    /// Converts literal token into an AST literal.
    pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
        Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
    }

    /// Converts arbitrary token into an AST literal.
    ///
    /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
    pub fn from_token(token: &Token) -> Result<Lit, LitError> {
        let lit = match token.uninterpolate().kind {
            token::Ident(name, false) if name.is_bool_lit() => {
                token::Lit::new(token::Bool, name, None)
            }
            token::Literal(lit) => lit,
            token::Interpolated(ref nt) => {
                if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
                    if let ast::ExprKind::Lit(lit) = &expr.kind {
                        return Ok(lit.clone());
                    }
                }
                return Err(LitError::NotLiteral);
            }
            _ => return Err(LitError::NotLiteral),
        };

        Lit::from_lit_token(lit, token.span)
    }

    /// Attempts to recover an AST literal from semantic literal.
    /// This function is used when the original token doesn't exist (e.g. the literal is created
    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
    pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
        Lit { token: kind.to_lit_token(), kind, span }
    }

    /// Losslessly convert an AST literal into a token.
    pub fn to_token(&self) -> Token {
        let kind = match self.token.kind {
            token::Bool => token::Ident(self.token.symbol, false),
            _ => token::Literal(self.token),
        };
        Token::new(kind, self.span)
    }
}

fn strip_underscores(symbol: Symbol) -> Symbol {
    // Do not allocate a new string unless necessary.
    let s = symbol.as_str();
    if s.contains('_') {
        let mut s = s.to_string();
        s.retain(|c| c != '_');
        return Symbol::intern(&s);
    }
    symbol
}

fn filtered_float_lit(
    symbol: Symbol,
    suffix: Option<Symbol>,
    base: u32,
) -> Result<LitKind, LitError> {
    debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base);
    if base != 10 {
        return Err(LitError::NonDecimalFloat(base));
    }
    Ok(match suffix {
        Some(suf) => LitKind::Float(
            symbol,
            ast::LitFloatType::Suffixed(match suf {
                sym::f32 => ast::FloatTy::F32,
                sym::f64 => ast::FloatTy::F64,
                _ => return Err(LitError::InvalidFloatSuffix),
            }),
        ),
        None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed),
    })
}

fn float_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
    debug!("float_lit: {:?}, {:?}", symbol, suffix);
    filtered_float_lit(strip_underscores(symbol), suffix, 10)
}

fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
    debug!("integer_lit: {:?}, {:?}", symbol, suffix);
    let symbol = strip_underscores(symbol);
    let s = symbol.as_str();

    let base = match s.as_bytes() {
        [b'0', b'x', ..] => 16,
        [b'0', b'o', ..] => 8,
        [b'0', b'b', ..] => 2,
        _ => 10,
    };

    let ty = match suffix {
        Some(suf) => match suf {
            sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize),
            sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8),
            sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16),
            sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32),
            sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64),
            sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128),
            sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize),
            sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8),
            sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16),
            sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32),
            sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64),
            sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128),
            // `1f64` and `2f32` etc. are valid float literals, and
            // `fxxx` looks more like an invalid float literal than invalid integer literal.
            _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
            _ => return Err(LitError::InvalidIntSuffix),
        },
        _ => ast::LitIntType::Unsuffixed,
    };

    let s = &s[if base != 10 { 2 } else { 0 }..];
    u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| {
        // Small bases are lexed as if they were base 10, e.g, the string
        // might be `0b10201`. This will cause the conversion above to fail,
        // but these kinds of errors are already reported by the lexer.
        let from_lexer =
            base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
        if from_lexer { LitError::LexerError } else { LitError::IntTooLarge }
    })
}
<|endoftext|>