summaryrefslogtreecommitdiffstats
path: root/third_party/rust/autocfg-0.1.6/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/autocfg-0.1.6/src/error.rs69
-rw-r--r--third_party/rust/autocfg-0.1.6/src/lib.rs329
-rw-r--r--third_party/rust/autocfg-0.1.6/src/tests.rs99
-rw-r--r--third_party/rust/autocfg-0.1.6/src/version.rs60
4 files changed, 557 insertions, 0 deletions
diff --git a/third_party/rust/autocfg-0.1.6/src/error.rs b/third_party/rust/autocfg-0.1.6/src/error.rs
new file mode 100644
index 0000000000..4624835451
--- /dev/null
+++ b/third_party/rust/autocfg-0.1.6/src/error.rs
@@ -0,0 +1,69 @@
+use std::error;
+use std::fmt;
+use std::io;
+use std::num;
+use std::str;
+
+/// A common error type for the `autocfg` crate.
+#[derive(Debug)]
+pub struct Error {
+ kind: ErrorKind,
+}
+
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ "AutoCfg error"
+ }
+
+ fn cause(&self) -> Option<&error::Error> {
+ match self.kind {
+ ErrorKind::Io(ref e) => Some(e),
+ ErrorKind::Num(ref e) => Some(e),
+ ErrorKind::Utf8(ref e) => Some(e),
+ ErrorKind::Other(_) => None,
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ match self.kind {
+ ErrorKind::Io(ref e) => e.fmt(f),
+ ErrorKind::Num(ref e) => e.fmt(f),
+ ErrorKind::Utf8(ref e) => e.fmt(f),
+ ErrorKind::Other(s) => s.fmt(f),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum ErrorKind {
+ Io(io::Error),
+ Num(num::ParseIntError),
+ Utf8(str::Utf8Error),
+ Other(&'static str),
+}
+
+pub fn from_io(e: io::Error) -> Error {
+ Error {
+ kind: ErrorKind::Io(e),
+ }
+}
+
+pub fn from_num(e: num::ParseIntError) -> Error {
+ Error {
+ kind: ErrorKind::Num(e),
+ }
+}
+
+pub fn from_utf8(e: str::Utf8Error) -> Error {
+ Error {
+ kind: ErrorKind::Utf8(e),
+ }
+}
+
+pub fn from_str(s: &'static str) -> Error {
+ Error {
+ kind: ErrorKind::Other(s),
+ }
+}
diff --git a/third_party/rust/autocfg-0.1.6/src/lib.rs b/third_party/rust/autocfg-0.1.6/src/lib.rs
new file mode 100644
index 0000000000..ea4ed03ca7
--- /dev/null
+++ b/third_party/rust/autocfg-0.1.6/src/lib.rs
@@ -0,0 +1,329 @@
+//! A Rust library for build scripts to automatically configure code based on
+//! compiler support. Code snippets are dynamically tested to see if the `rustc`
+//! will accept them, rather than hard-coding specific version support.
+//!
+//!
+//! ## Usage
+//!
+//! Add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [build-dependencies]
+//! autocfg = "0.1"
+//! ```
+//!
+//! Then use it in your `build.rs` script to detect compiler features. For
+//! example, to test for 128-bit integer support, it might look like:
+//!
+//! ```rust
+//! extern crate autocfg;
+//!
+//! fn main() {
+//! # // Normally, cargo will set `OUT_DIR` for build scripts.
+//! # std::env::set_var("OUT_DIR", "target");
+//! let ac = autocfg::new();
+//! ac.emit_has_type("i128");
+//!
+//! // (optional) We don't need to rerun for anything external.
+//! autocfg::rerun_path(file!());
+//! }
+//! ```
+//!
+//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line
+//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the
+//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that
+//! should only be used when the compiler supports it.
+
+#![deny(missing_debug_implementations)]
+#![deny(missing_docs)]
+// allow future warnings that can't be fixed while keeping 1.0 compatibility
+#![allow(unknown_lints)]
+#![allow(bare_trait_objects)]
+#![allow(ellipsis_inclusive_range_patterns)]
+#![allow(warnings)]
+
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io::{stderr, Write};
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+#[allow(deprecated)]
+use std::sync::atomic::ATOMIC_USIZE_INIT;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+mod error;
+pub use error::Error;
+
+mod version;
+use version::Version;
+
+#[cfg(test)]
+mod tests;
+
+/// Helper to detect compiler features for `cfg` output in build scripts.
+#[derive(Clone, Debug)]
+pub struct AutoCfg {
+ out_dir: PathBuf,
+ rustc: PathBuf,
+ rustc_version: Version,
+ target: Option<OsString>,
+ no_std: bool,
+}
+
+/// Writes a config flag for rustc on standard out.
+///
+/// This looks like: `cargo:rustc-cfg=CFG`
+///
+/// Cargo will use this in arguments to rustc, like `--cfg CFG`.
+pub fn emit(cfg: &str) {
+ println!("cargo:rustc-cfg={}", cfg);
+}
+
+/// Writes a line telling Cargo to rerun the build script if `path` changes.
+///
+/// This looks like: `cargo:rerun-if-changed=PATH`
+///
+/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier
+/// versions of cargo will simply ignore the directive.
+pub fn rerun_path(path: &str) {
+ println!("cargo:rerun-if-changed={}", path);
+}
+
+/// Writes a line telling Cargo to rerun the build script if the environment
+/// variable `var` changes.
+///
+/// This looks like: `cargo:rerun-if-env-changed=VAR`
+///
+/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier
+/// versions of cargo will simply ignore the directive.
+pub fn rerun_env(var: &str) {
+ println!("cargo:rerun-if-env-changed={}", var);
+}
+
+/// Create a new `AutoCfg` instance.
+///
+/// # Panics
+///
+/// Panics if `AutoCfg::new()` returns an error.
+pub fn new() -> AutoCfg {
+ AutoCfg::new().unwrap()
+}
+
+impl AutoCfg {
+ /// Create a new `AutoCfg` instance.
+ ///
+ /// # Common errors
+ ///
+ /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
+ /// - The version output from `rustc` can't be parsed.
+ /// - `OUT_DIR` is not set in the environment, or is not a writable directory.
+ ///
+ pub fn new() -> Result<Self, Error> {
+ match env::var_os("OUT_DIR") {
+ Some(d) => Self::with_dir(d),
+ None => Err(error::from_str("no OUT_DIR specified!")),
+ }
+ }
+
+ /// Create a new `AutoCfg` instance with the specified output directory.
+ ///
+ /// # Common errors
+ ///
+ /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`.
+ /// - The version output from `rustc` can't be parsed.
+ /// - `dir` is not a writable directory.
+ ///
+ pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
+ let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
+ let rustc: PathBuf = rustc.into();
+ let rustc_version = try!(Version::from_rustc(&rustc));
+
+ // Sanity check the output directory
+ let dir = dir.into();
+ let meta = try!(fs::metadata(&dir).map_err(error::from_io));
+ if !meta.is_dir() || meta.permissions().readonly() {
+ return Err(error::from_str("output path is not a writable directory"));
+ }
+
+ let mut ac = AutoCfg {
+ out_dir: dir,
+ rustc: rustc,
+ rustc_version: rustc_version,
+ target: env::var_os("TARGET"),
+ no_std: false,
+ };
+
+ // Sanity check with and without `std`.
+ if !ac.probe("").unwrap_or(false) {
+ ac.no_std = true;
+ if !ac.probe("").unwrap_or(false) {
+ // Neither worked, so assume nothing...
+ ac.no_std = false;
+ let warning = b"warning: autocfg could not probe for `std`\n";
+ stderr().write_all(warning).ok();
+ }
+ }
+ Ok(ac)
+ }
+
+ /// Test whether the current `rustc` reports a version greater than
+ /// or equal to "`major`.`minor`".
+ pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool {
+ self.rustc_version >= Version::new(major, minor, 0)
+ }
+
+ /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`,
+ /// if the current `rustc` is at least that version.
+ pub fn emit_rustc_version(&self, major: usize, minor: usize) {
+ if self.probe_rustc_version(major, minor) {
+ emit(&format!("rustc_{}_{}", major, minor));
+ }
+ }
+
+ fn probe<T: AsRef<[u8]>>(&self, code: T) -> Result<bool, Error> {
+ #[allow(deprecated)]
+ static ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+ let id = ID.fetch_add(1, Ordering::Relaxed);
+ let mut command = Command::new(&self.rustc);
+ command
+ .arg("--crate-name")
+ .arg(format!("probe{}", id))
+ .arg("--crate-type=lib")
+ .arg("--out-dir")
+ .arg(&self.out_dir)
+ .arg("--emit=llvm-ir");
+
+ if let Some(target) = self.target.as_ref() {
+ command.arg("--target").arg(target);
+ }
+
+ command.arg("-").stdin(Stdio::piped()).stderr(Stdio::null());
+ let mut child = try!(command.spawn().map_err(error::from_io));
+ let mut stdin = child.stdin.take().expect("rustc stdin");
+
+ if self.no_std {
+ try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io));
+ }
+ try!(stdin.write_all(code.as_ref()).map_err(error::from_io));
+ drop(stdin);
+
+ let status = try!(child.wait().map_err(error::from_io));
+ Ok(status.success())
+ }
+
+ /// Tests whether the given sysroot crate can be used.
+ ///
+ /// The test code is subject to change, but currently looks like:
+ ///
+ /// ```ignore
+ /// extern crate CRATE as probe;
+ /// ```
+ pub fn probe_sysroot_crate(&self, name: &str) -> bool {
+ self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33
+ .unwrap_or(false)
+ }
+
+ /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true.
+ pub fn emit_sysroot_crate(&self, name: &str) {
+ if self.probe_sysroot_crate(name) {
+ emit(&format!("has_{}", mangle(name)));
+ }
+ }
+
+ /// Tests whether the given path can be used.
+ ///
+ /// The test code is subject to change, but currently looks like:
+ ///
+ /// ```ignore
+ /// pub use PATH;
+ /// ```
+ pub fn probe_path(&self, path: &str) -> bool {
+ self.probe(format!("pub use {};", path)).unwrap_or(false)
+ }
+
+ /// Emits a config value `has_PATH` if `probe_path` returns true.
+ ///
+ /// Any non-identifier characters in the `path` will be replaced with
+ /// `_` in the generated config value.
+ pub fn emit_has_path(&self, path: &str) {
+ if self.probe_path(path) {
+ emit(&format!("has_{}", mangle(path)));
+ }
+ }
+
+ /// Emits the given `cfg` value if `probe_path` returns true.
+ pub fn emit_path_cfg(&self, path: &str, cfg: &str) {
+ if self.probe_path(path) {
+ emit(cfg);
+ }
+ }
+
+ /// Tests whether the given trait can be used.
+ ///
+ /// The test code is subject to change, but currently looks like:
+ ///
+ /// ```ignore
+ /// pub trait Probe: TRAIT + Sized {}
+ /// ```
+ pub fn probe_trait(&self, name: &str) -> bool {
+ self.probe(format!("pub trait Probe: {} + Sized {{}}", name))
+ .unwrap_or(false)
+ }
+
+ /// Emits a config value `has_TRAIT` if `probe_trait` returns true.
+ ///
+ /// Any non-identifier characters in the trait `name` will be replaced with
+ /// `_` in the generated config value.
+ pub fn emit_has_trait(&self, name: &str) {
+ if self.probe_trait(name) {
+ emit(&format!("has_{}", mangle(name)));
+ }
+ }
+
+ /// Emits the given `cfg` value if `probe_trait` returns true.
+ pub fn emit_trait_cfg(&self, name: &str, cfg: &str) {
+ if self.probe_trait(name) {
+ emit(cfg);
+ }
+ }
+
+ /// Tests whether the given type can be used.
+ ///
+ /// The test code is subject to change, but currently looks like:
+ ///
+ /// ```ignore
+ /// pub type Probe = TYPE;
+ /// ```
+ pub fn probe_type(&self, name: &str) -> bool {
+ self.probe(format!("pub type Probe = {};", name))
+ .unwrap_or(false)
+ }
+
+ /// Emits a config value `has_TYPE` if `probe_type` returns true.
+ ///
+ /// Any non-identifier characters in the type `name` will be replaced with
+ /// `_` in the generated config value.
+ pub fn emit_has_type(&self, name: &str) {
+ if self.probe_type(name) {
+ emit(&format!("has_{}", mangle(name)));
+ }
+ }
+
+ /// Emits the given `cfg` value if `probe_type` returns true.
+ pub fn emit_type_cfg(&self, name: &str, cfg: &str) {
+ if self.probe_type(name) {
+ emit(cfg);
+ }
+ }
+}
+
+fn mangle(s: &str) -> String {
+ s.chars()
+ .map(|c| match c {
+ 'A'...'Z' | 'a'...'z' | '0'...'9' => c,
+ _ => '_',
+ })
+ .collect()
+}
diff --git a/third_party/rust/autocfg-0.1.6/src/tests.rs b/third_party/rust/autocfg-0.1.6/src/tests.rs
new file mode 100644
index 0000000000..304d989bcb
--- /dev/null
+++ b/third_party/rust/autocfg-0.1.6/src/tests.rs
@@ -0,0 +1,99 @@
+use super::AutoCfg;
+
+impl AutoCfg {
+ fn core_std(&self, path: &str) -> String {
+ let krate = if self.no_std { "core" } else { "std" };
+ format!("{}::{}", krate, path)
+ }
+}
+
+#[test]
+fn autocfg_version() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ println!("version: {:?}", ac.rustc_version);
+ assert!(ac.probe_rustc_version(1, 0));
+}
+
+#[test]
+fn version_cmp() {
+ use super::version::Version;
+ let v123 = Version::new(1, 2, 3);
+
+ assert!(Version::new(1, 0, 0) < v123);
+ assert!(Version::new(1, 2, 2) < v123);
+ assert!(Version::new(1, 2, 3) == v123);
+ assert!(Version::new(1, 2, 4) > v123);
+ assert!(Version::new(1, 10, 0) > v123);
+ assert!(Version::new(2, 0, 0) > v123);
+}
+
+#[test]
+fn probe_add() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ let add = ac.core_std("ops::Add");
+ let add_rhs = ac.core_std("ops::Add<i32>");
+ let add_rhs_output = ac.core_std("ops::Add<i32, Output = i32>");
+ assert!(ac.probe_path(&add));
+ assert!(ac.probe_trait(&add));
+ assert!(ac.probe_trait(&add_rhs));
+ assert!(ac.probe_trait(&add_rhs_output));
+ assert!(ac.probe_type(&add_rhs_output));
+}
+
+#[test]
+fn probe_as_ref() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ let as_ref = ac.core_std("convert::AsRef");
+ let as_ref_str = ac.core_std("convert::AsRef<str>");
+ assert!(ac.probe_path(&as_ref));
+ assert!(ac.probe_trait(&as_ref_str));
+ assert!(ac.probe_type(&as_ref_str));
+}
+
+#[test]
+fn probe_i128() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ let missing = !ac.probe_rustc_version(1, 26);
+ let i128_path = ac.core_std("i128");
+ assert!(missing ^ ac.probe_path(&i128_path));
+ assert!(missing ^ ac.probe_type("i128"));
+}
+
+#[test]
+fn probe_sum() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ let missing = !ac.probe_rustc_version(1, 12);
+ let sum = ac.core_std("iter::Sum");
+ let sum_i32 = ac.core_std("iter::Sum<i32>");
+ assert!(missing ^ ac.probe_path(&sum));
+ assert!(missing ^ ac.probe_trait(&sum));
+ assert!(missing ^ ac.probe_trait(&sum_i32));
+ assert!(missing ^ ac.probe_type(&sum_i32));
+}
+
+#[test]
+fn probe_std() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ assert_eq!(ac.probe_sysroot_crate("std"), !ac.no_std);
+}
+
+#[test]
+fn probe_alloc() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ let missing = !ac.probe_rustc_version(1, 36);
+ assert!(missing ^ ac.probe_sysroot_crate("alloc"));
+}
+
+#[test]
+fn probe_bad_sysroot_crate() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ assert!(!ac.probe_sysroot_crate("doesnt_exist"));
+}
+
+#[test]
+fn probe_no_std() {
+ let ac = AutoCfg::with_dir("target").unwrap();
+ assert!(ac.probe_type("i32"));
+ assert!(ac.probe_type("[i32]"));
+ assert_eq!(ac.probe_type("Vec<i32>"), !ac.no_std);
+}
diff --git a/third_party/rust/autocfg-0.1.6/src/version.rs b/third_party/rust/autocfg-0.1.6/src/version.rs
new file mode 100644
index 0000000000..378c21e61e
--- /dev/null
+++ b/third_party/rust/autocfg-0.1.6/src/version.rs
@@ -0,0 +1,60 @@
+use std::path::Path;
+use std::process::Command;
+use std::str;
+
+use super::{error, Error};
+
+/// A version structure for making relative comparisons.
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Version {
+ major: usize,
+ minor: usize,
+ patch: usize,
+}
+
+impl Version {
+ /// Creates a `Version` instance for a specific `major.minor.patch` version.
+ pub fn new(major: usize, minor: usize, patch: usize) -> Self {
+ Version {
+ major: major,
+ minor: minor,
+ patch: patch,
+ }
+ }
+
+ pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
+ // Get rustc's verbose version
+ let output = try!(Command::new(rustc)
+ .args(&["--version", "--verbose"])
+ .output()
+ .map_err(error::from_io));
+ if !output.status.success() {
+ return Err(error::from_str("could not execute rustc"));
+ }
+ let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8));
+
+ // Find the release line in the verbose version output.
+ let release = match output.lines().find(|line| line.starts_with("release: ")) {
+ Some(line) => &line["release: ".len()..],
+ None => return Err(error::from_str("could not find rustc release")),
+ };
+
+ // Strip off any extra channel info, e.g. "-beta.N", "-nightly"
+ let version = match release.find('-') {
+ Some(i) => &release[..i],
+ None => release,
+ };
+
+ // Split the version into semver components.
+ let mut iter = version.splitn(3, '.');
+ let major = try!(iter.next().ok_or(error::from_str("missing major version")));
+ let minor = try!(iter.next().ok_or(error::from_str("missing minor version")));
+ let patch = try!(iter.next().ok_or(error::from_str("missing patch version")));
+
+ Ok(Version::new(
+ try!(major.parse().map_err(error::from_num)),
+ try!(minor.parse().map_err(error::from_num)),
+ try!(patch.parse().map_err(error::from_num)),
+ ))
+ }
+}