Wrap part of //aos:init for Rust

Just enough to run tests for now.

Change-Id: I714fbabfe713b34494a0a47a5679c409cce211c4
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
diff --git a/aos/BUILD b/aos/BUILD
index a1c92e7..5fcb7cf 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -178,6 +178,18 @@
     ],
 )
 
+autocxx_library(
+    name = "init_rs",
+    srcs = ["init.rs"],
+    crate_name = "aos_init",
+    libs = [
+        ":init",
+    ],
+    override_cc_toolchain = "@llvm_toolchain//:cc-clang-x86_64-linux",
+    target_compatible_with = ["//tools/platforms/rust:has_support"],
+    visibility = ["//visibility:public"],
+)
+
 cc_library(
     name = "realtime",
     srcs = [
diff --git a/aos/init.cc b/aos/init.cc
index 3b298fa..9b00f1c 100644
--- a/aos/init.cc
+++ b/aos/init.cc
@@ -39,4 +39,25 @@
   initialized = true;
 }
 
+void InitFromRust(const char *argv0) {
+  CHECK(!IsInitialized()) << "Only initialize once.";
+
+  FLAGS_logtostderr = true;
+
+  google::InitGoogleLogging(argv0);
+
+  // TODO(Brian): Provide a way for Rust to configure C++ flags.
+  char fake_argv0_val[] = "rust";
+  char *fake_argv0 = fake_argv0_val;
+  char **fake_argv = &fake_argv0;
+  int fake_argc = 1;
+  gflags::ParseCommandLineFlags(&fake_argc, &fake_argv, true);
+
+  // TODO(Brian): Where should Rust binaries be configured to write coredumps?
+
+  // TODO(Brian): Figure out what to do with allocator hooks for C++ and Rust.
+
+  initialized = true;
+}
+
 }  // namespace aos
diff --git a/aos/init.h b/aos/init.h
index 1e2b7a4..29480eb 100644
--- a/aos/init.h
+++ b/aos/init.h
@@ -10,6 +10,11 @@
 // ShmEventLoop can confirm the world was initialized before running.
 bool IsInitialized();
 
+// A special initialization function that initializes the C++ parts in a way
+// compatible with Rust. This requires careful coordination with `:init_rs`, do
+// not use it from anywhere else.
+void InitFromRust(const char *argv0);
+
 }  // namespace aos
 
 #endif  // AOS_INIT_H_
diff --git a/aos/init.rs b/aos/init.rs
new file mode 100644
index 0000000..8a5f262
--- /dev/null
+++ b/aos/init.rs
@@ -0,0 +1,29 @@
+use std::{ffi::CString, sync::Once};
+
+autocxx::include_cpp! (
+#include "aos/init.h"
+
+safety!(unsafe)
+
+generate!("aos::InitFromRust")
+);
+
+/// Initializes things for a test.
+///
+/// TODO(Brian): Should we provide a proc macro attribute that handles calling this?
+///
+/// # Panics
+///
+/// Panics if non-test initialization has already been performed.
+pub fn test_init() {
+    static ONCE: Once = Once::new();
+    ONCE.call_once(|| {
+        let argv0 = std::env::args().next().expect("must have argv[0]");
+        let argv0 = CString::new(argv0).expect("argv[0] may not have NUL");
+        // SAFETY: argv0 is a NUL-terminated string.
+        unsafe { ffi::aos::InitFromRust(argv0.as_ptr()) };
+    });
+
+    // TODO(Brian): Do we want any of the other stuff that `:gtest_main` has?
+    // TODO(Brian): Call `aos::SetShmBase` like `:gtest_main` does.
+}