Squashed 'third_party/rules_rust/' content from commit bf59038ca

git-subtree-dir: third_party/rules_rust
git-subtree-split: bf59038cac11798cbaef9f3bf965bad8182b97fa
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I5a20e403203d670df467ea97dde9a4ac40339a8d
diff --git a/tools/rustfmt/srcs/lib.rs b/tools/rustfmt/srcs/lib.rs
new file mode 100644
index 0000000..ad2e86a
--- /dev/null
+++ b/tools/rustfmt/srcs/lib.rs
@@ -0,0 +1,74 @@
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+/// The expected extension of rustfmt manifest files generated by `rustfmt_aspect`.
+pub const RUSTFMT_MANIFEST_EXTENSION: &str = "rustfmt";
+
+/// Generate an absolute path to a file without resolving symlinks
+fn absolutify_existing<T: AsRef<Path>>(path: &T) -> std::io::Result<PathBuf> {
+    let absolute_path = if path.as_ref().is_absolute() {
+        path.as_ref().to_owned()
+    } else {
+        std::env::current_dir()
+            .expect("Failed to get working directory")
+            .join(path)
+    };
+    std::fs::metadata(&absolute_path).map(|_| absolute_path)
+}
+
+/// A struct containing details used for executing rustfmt.
+#[derive(Debug)]
+pub struct RustfmtConfig {
+    /// The rustfmt binary from the currently active toolchain
+    pub rustfmt: PathBuf,
+
+    /// The rustfmt config file containing rustfmt settings.
+    /// https://rust-lang.github.io/rustfmt/
+    pub config: PathBuf,
+}
+
+/// Parse command line arguments and environment variables to
+/// produce config data for running rustfmt.
+pub fn parse_rustfmt_config() -> RustfmtConfig {
+    RustfmtConfig {
+        rustfmt: absolutify_existing(&env!("RUSTFMT")).expect("Unable to find rustfmt binary"),
+        config: absolutify_existing(&env!("RUSTFMT_CONFIG"))
+            .expect("Unable to find rustfmt config file"),
+    }
+}
+
+/// A struct of target specific information for use in running `rustfmt`.
+#[derive(Debug)]
+pub struct RustfmtManifest {
+    /// The Rust edition of the Bazel target
+    pub edition: String,
+
+    /// A list of all (non-generated) source files for formatting.
+    pub sources: Vec<String>,
+}
+
+/// Parse rustfmt flags from a manifest generated by builds using `rustfmt_aspect`.
+pub fn parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest {
+    let content = fs::read_to_string(manifest)
+        .unwrap_or_else(|_| panic!("Failed to read rustfmt manifest: {}", manifest.display()));
+
+    let mut lines: Vec<String> = content
+        .split('\n')
+        .into_iter()
+        .filter(|s| !s.is_empty())
+        .map(|s| s.to_owned())
+        .collect();
+
+    let edition = lines
+        .pop()
+        .expect("There should always be at least 1 line in the manifest");
+    edition
+        .parse::<i32>()
+        .expect("The edition should be a numeric value. eg `2018`.");
+
+    RustfmtManifest {
+        edition,
+        sources: lines,
+    }
+}