Add rust toolchains

Signed-off-by: Ravago Jones <ravagojones@gmail.com>
Change-Id: I5f36ff152b01bbb628dea45175294cf7f52bb15f
diff --git a/WORKSPACE b/WORKSPACE
index 4aaad5b..96aa929 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -226,6 +226,8 @@
     #"//tools/cpp:cc-toolchain-cortex-m4f-k22",
     "//tools/python:python_toolchain",
     "//tools/go:noop_go_toolchain",
+    "//tools/rust:rust-toolchain-roborio",
+    "//tools/rust:noop_rust_toolchain",
 )
 
 load("//tools/ci:repo_defs.bzl", "ci_configure")
@@ -777,6 +779,29 @@
     urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.5/rules_webtesting.tar.gz"],
 )
 
+http_archive(
+    name = "rules_rust",
+    sha256 = "531bdd470728b61ce41cf7604dc4f9a115983e455d46ac1d0c1632f613ab9fc3",
+    strip_prefix = "rules_rust-d8238877c0e552639d3e057aadd6bfcf37592408",
+    urls = [
+        # `main` branch as of 2021-08-23
+        "https://github.com/bazelbuild/rules_rust/archive/d8238877c0e552639d3e057aadd6bfcf37592408.tar.gz",
+    ],
+)
+
+load("@rules_rust//rust:repositories.bzl", "rust_repository_set")
+
+rust_repository_set(
+    name = "rust",
+    edition = "2021",
+    exec_triple = "x86_64-unknown-linux-gnu",
+    extra_target_triples = [
+        "arm-unknown-linux-gnueabi",
+        "armv7-unknown-linux-gnueabihf",
+    ],
+    version = "1.56.1",
+)
+
 # Flatbuffers
 local_repository(
     name = "com_github_google_flatbuffers",
diff --git a/build_tests/BUILD b/build_tests/BUILD
index ca34de2..6a81509 100644
--- a/build_tests/BUILD
+++ b/build_tests/BUILD
@@ -2,6 +2,7 @@
 load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_py_library")
 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 load("//tools/build_rules:apache.bzl", "apache_wrapper")
+load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
 
 cc_test(
     name = "gflags_build_test",
@@ -126,3 +127,23 @@
     binary = ":dummy_http_server",
     target_compatible_with = ["@platforms//cpu:x86_64"],
 )
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["hello_lib.rs"],
+    target_compatible_with = ["@platforms//os:linux"],
+)
+
+rust_test(
+    name = "hello_lib_test",
+    srcs = ["hello_lib.rs"],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":hello_lib"],
+)
+
+rust_binary(
+    name = "rust_hello",
+    srcs = ["rust_hello.rs"],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":hello_lib"],
+)
diff --git a/build_tests/hello_lib.rs b/build_tests/hello_lib.rs
new file mode 100644
index 0000000..6374ce6
--- /dev/null
+++ b/build_tests/hello_lib.rs
@@ -0,0 +1,24 @@
+pub struct Greeter {
+        greeting: String,
+}
+
+impl Greeter {
+    pub fn new(greeting: &str) -> Greeter {
+        Greeter { greeting: greeting.to_string(), }
+    }
+
+    pub fn greet(&self, thing: &str) -> String {
+        format!("{} {}", &self.greeting, thing)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::Greeter;
+
+    #[test]
+    fn test_greeting() {
+        let hello = Greeter::new("Hi");
+        assert_eq!("Hi Rust", hello.greet("Rust"));
+    }
+}
diff --git a/build_tests/rust_hello.rs b/build_tests/rust_hello.rs
new file mode 100644
index 0000000..6c6bf9f
--- /dev/null
+++ b/build_tests/rust_hello.rs
@@ -0,0 +1,21 @@
+extern crate hello_lib;
+
+extern "C" {
+    fn sqrt(x: f64) -> f64;
+}
+
+fn main() {
+  let hello = hello_lib::Greeter::new("Hello");
+  println!("{},\n{}", hello.greet("world"), hello.greet("bazel"));
+
+  let mut numbers = Vec::new();
+  for i in 1..=10 {
+      numbers.push(i);
+  }
+  println!("{:?}", numbers);
+
+  let words = vec!["foo", "bar", "baz"];
+  println!("{:?}", words);
+
+  println!("sqrt(4) = {}", unsafe { sqrt(4.0) });
+}
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index 17f218e..6ff661a 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -76,6 +76,7 @@
     srcs = [
         ":flags_compiler_inputs",
         "//tools/cpp/arm-frc-linux-gnueabi:as",
+        "//tools/cpp/arm-frc-linux-gnueabi:libs",
         "//tools/cpp/arm-frc-linux-gnueabi:tool-wrappers",
         "@arm_frc_linux_gnueabi_repo//:compiler_pieces",
     ],
diff --git a/tools/dependency_rewrite b/tools/dependency_rewrite
index 3cafe9b..cc1de8c 100644
--- a/tools/dependency_rewrite
+++ b/tools/dependency_rewrite
@@ -5,6 +5,7 @@
 rewrite dl.google.com/(.*) software.frc971.org/Build-Dependencies/dl.google.com/$1
 rewrite mirror.bazel.build/(.*) software.frc971.org/Build-Dependencies/mirror.bazel.build/$1
 rewrite nodejs.org/(.*) software.frc971.org/Build-Dependencies/nodejs.org/$1
+rewrite static.rust-lang.org/(.*) software.frc971.org/Build-Dependencies/static.rust-lang.org/$1
 allow golang.org
 
 allow software.frc971.org
diff --git a/tools/platforms/BUILD b/tools/platforms/BUILD
index bb53ee1..d6a63c7 100644
--- a/tools/platforms/BUILD
+++ b/tools/platforms/BUILD
@@ -6,6 +6,7 @@
         "@platforms//os:linux",
         "@platforms//cpu:x86_64",
         "//tools/platforms/go:has_support",
+        "//tools/platforms/rust:has_support",
     ],
 )
 
@@ -16,6 +17,7 @@
         "@platforms//cpu:armv7",
         "//tools/platforms/hardware:raspberry_pi",
         "//tools/platforms/go:lacks_support",
+        "//tools/platforms/rust:has_support",
     ],
 )
 
@@ -25,6 +27,7 @@
         "@platforms//os:linux",
         "@platforms//cpu:arm64",
         "//tools/platforms/go:lacks_support",
+        "//tools/platforms/rust:has_support",
     ],
 )
 
@@ -35,6 +38,7 @@
         "@platforms//cpu:armv7",
         "//tools/platforms/hardware:roborio",
         "//tools/platforms/go:lacks_support",
+        "//tools/platforms/rust:has_support",
     ],
 )
 
@@ -44,6 +48,7 @@
         "@platforms//os:none",
         "//tools/platforms/hardware:cortex_m4f",
         "//tools/platforms/go:lacks_support",
+        "//tools/platforms/rust:lacks_support",
     ],
 )
 
@@ -53,6 +58,7 @@
         "@platforms//os:none",
         "//tools/platforms/hardware:cortex_m0plus",
         "//tools/platforms/go:lacks_support",
+        "//tools/platforms/rust:lacks_support",
     ],
 )
 
diff --git a/tools/platforms/rust/BUILD b/tools/platforms/rust/BUILD
new file mode 100644
index 0000000..5b4745f
--- /dev/null
+++ b/tools/platforms/rust/BUILD
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+constraint_setting(name = "rust_support")
+
+constraint_value(
+    name = "has_support",
+    constraint_setting = ":rust_support",
+)
+
+constraint_value(
+    name = "lacks_support",
+    constraint_setting = ":rust_support",
+)
diff --git a/tools/rust/BUILD b/tools/rust/BUILD
new file mode 100644
index 0000000..a652530
--- /dev/null
+++ b/tools/rust/BUILD
@@ -0,0 +1,73 @@
+load("@rules_rust//rust:toolchain.bzl", "rust_stdlib_filegroup", "rust_toolchain")
+load("@bazel_skylib//rules:write_file.bzl", "write_file")
+
+# Similar to the one automatically generated by @rust, but with the correct
+# hardware platform configured.
+toolchain(
+    name = "rust-toolchain-roborio",
+    exec_compatible_with = [
+        "@platforms//os:linux",
+        "@platforms//cpu:x86_64",
+    ],
+    target_compatible_with = [
+        "@platforms//os:linux",
+        "//tools/platforms/hardware:roborio",
+    ],
+    toolchain = "@rust//:toolchain_for_arm-unknown-linux-gnueabi_impl",
+    toolchain_type = "@rules_rust//rust:toolchain",
+)
+
+# The remainder of this file exists to create a NOOP toolchain for Rust on
+# platforms that don't support Rust. We can probably get rid of this once
+# https://github.com/bazelbuild/bazel/issues/12897 is fixed.
+
+write_file(
+    name = "noop_error_exit",
+    out = "noop_error_exit.sh",
+    content = [
+        "#!/bin/bash",
+        "echo 'This should never be executed. Something went wrong.' >&2",
+        "echo 'This NOOP Rust toolchain should never be executed. Something went wrong.' >&2",
+        "echo 'Check that your target has `target_compatible_with` set to a platform that supports Rust.' >&2",
+        "exit 1",
+    ],
+    is_executable = True,
+)
+
+rust_stdlib_filegroup(
+    name = "empty_stdlib",
+    srcs = [":noop_error_exit"],
+)
+
+rust_toolchain(
+    name = "noop_rust_toolchain_impl",
+    binary_ext = "",
+    cargo = ":noop_error_exit",
+    clippy_driver = ":noop_error_exit",
+    default_edition = "2021",
+    dylib_ext = ".so",
+    exec_triple = "none",
+    os = "none",
+    rust_doc = ":noop_error_exit",
+    rust_lib = ":empty_stdlib",
+    rustc = ":noop_error_exit",
+    rustc_lib = ":noop_error_exit",
+    rustc_srcs = None,
+    rustfmt = ":noop_error_exit",
+    staticlib_ext = ".a",
+    stdlib_linkflags = [],
+    tags = ["manual"],
+    target_triple = "none",
+)
+
+toolchain(
+    name = "noop_rust_toolchain",
+    exec_compatible_with = [
+        "@platforms//os:linux",
+    ],
+    target_compatible_with = [
+        "//tools/platforms/rust:lacks_support",
+    ],
+    toolchain = ":noop_rust_toolchain_impl",
+    toolchain_type = "@rules_rust//rust:toolchain",
+)