Rust substitutions and config values

Initial support for Rust-specific substitutions and config values.

Change-Id: Iefa9c12056d9ed792ebe1fcb6822636604058747
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/4881
Commit-Queue: Julie Hockett <juliehockett@google.com>
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/build/gen.py b/build/gen.py
index 766969f..943f2e8 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -515,6 +515,7 @@
         'tools/gn/pool.cc',
         'tools/gn/qt_creator_writer.cc',
         'tools/gn/runtime_deps.cc',
+        'tools/gn/rust_substitution_type.cc',
         'tools/gn/scheduler.cc',
         'tools/gn/scope.cc',
         'tools/gn/scope_per_file_provider.cc',
diff --git a/tools/gn/config_values.cc b/tools/gn/config_values.cc
index 5cdfa7a..85de7e4 100644
--- a/tools/gn/config_values.cc
+++ b/tools/gn/config_values.cc
@@ -34,6 +34,8 @@
   VectorAppend(&ldflags_, append.ldflags_);
   VectorAppend(&lib_dirs_, append.lib_dirs_);
   VectorAppend(&libs_, append.libs_);
+  VectorAppend(&rustflags_, append.rustflags_);
+  VectorAppend(&rustenv_, append.rustenv_);
 
   // Only append precompiled header if there isn't one. It might be nice to
   // throw an error if there are conflicting precompiled headers, but that
diff --git a/tools/gn/config_values.h b/tools/gn/config_values.h
index bcab53c..86eea6c 100644
--- a/tools/gn/config_values.h
+++ b/tools/gn/config_values.h
@@ -45,6 +45,8 @@
   DIR_VALUES_ACCESSOR(include_dirs)
   STRING_VALUES_ACCESSOR(ldflags)
   DIR_VALUES_ACCESSOR(lib_dirs)
+  STRING_VALUES_ACCESSOR(rustflags)
+  STRING_VALUES_ACCESSOR(rustenv)
   // =================================================================
   // IMPORTANT: If you add a new one, be sure to update AppendValues()
   //            and command_desc.cc.
@@ -81,6 +83,8 @@
   std::vector<std::string> ldflags_;
   std::vector<SourceDir> lib_dirs_;
   std::vector<LibFile> libs_;
+  std::vector<std::string> rustflags_;
+  std::vector<std::string> rustenv_;
   // If you add a new one, be sure to update AppendValues().
 
   std::string precompiled_header_;
diff --git a/tools/gn/rust_substitution_type.cc b/tools/gn/rust_substitution_type.cc
new file mode 100644
index 0000000..83ddbf5
--- /dev/null
+++ b/tools/gn/rust_substitution_type.cc
@@ -0,0 +1,47 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tools/gn/rust_substitution_type.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "tools/gn/err.h"
+#include "tools/gn/substitution_type.h"
+
+const SubstitutionTypes RustSubstitutions = {
+    &kRustSubstitutionCrateName,       &kRustSubstitutionCrateType,
+    &kRustSubstitutionEdition,         &kRustSubstitutionExterns,
+    &kRustSubstitutionOutputExtension, &kRustSubstitutionOutputPrefix,
+    &kRustSubstitutionRustDeps,        &kRustSubstitutionRustFlags,
+    &kRustSubstitutionRustEnv,
+};
+
+// Valid for Rust tools.
+const Substitution kRustSubstitutionCrateName = {"{{crate_name}}",
+                                                 "crate_name"};
+const Substitution kRustSubstitutionCrateType = {"{{crate_type}}",
+                                                 "crate_type"};
+const Substitution kRustSubstitutionEdition = {"{{edition}}", "edition"};
+const Substitution kRustSubstitutionExterns = {"{{externs}}", "externs"};
+const Substitution kRustSubstitutionOutputExtension = {
+    "{{rustc_output_extension}}", "rustc_output_extension"};
+const Substitution kRustSubstitutionOutputPrefix = {"{{rustc_output_prefix}}",
+                                                    "rustc_output_prefix"};
+const Substitution kRustSubstitutionRustDeps = {"{{rustdeps}}", "rustdeps"};
+const Substitution kRustSubstitutionRustEnv = {"{{rustenv}}", "rustenv"};
+const Substitution kRustSubstitutionRustFlags = {"{{rustflags}}", "rustflags"};
+
+bool IsValidRustSubstitution(const Substitution* type) {
+  return IsValidToolSubstitution(type) || IsValidSourceSubstitution(type) ||
+         type == &kRustSubstitutionCrateName ||
+         type == &kRustSubstitutionCrateType ||
+         type == &kRustSubstitutionEdition ||
+         type == &kRustSubstitutionExterns ||
+         type == &kRustSubstitutionOutputExtension ||
+         type == &kRustSubstitutionOutputPrefix ||
+         type == &kRustSubstitutionRustDeps ||
+         type == &kRustSubstitutionRustEnv ||
+         type == &kRustSubstitutionRustFlags;
+}
\ No newline at end of file
diff --git a/tools/gn/rust_substitution_type.h b/tools/gn/rust_substitution_type.h
new file mode 100644
index 0000000..827f5d6
--- /dev/null
+++ b/tools/gn/rust_substitution_type.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_RUST_SUBSTITUTION_TYPE_H_
+#define TOOLS_GN_RUST_SUBSTITUTION_TYPE_H_
+
+#include <set>
+#include <vector>
+
+#include "tools/gn/substitution_type.h"
+
+// The set of substitutions available to Rust tools.
+extern const SubstitutionTypes RustSubstitutions;
+
+// Valid for Rust tools.
+extern const Substitution kRustSubstitutionCrateName;
+extern const Substitution kRustSubstitutionCrateType;
+extern const Substitution kRustSubstitutionEdition;
+extern const Substitution kRustSubstitutionExterns;
+extern const Substitution kRustSubstitutionOutputExtension;
+extern const Substitution kRustSubstitutionOutputPrefix;
+extern const Substitution kRustSubstitutionRustDeps;
+extern const Substitution kRustSubstitutionRustEnv;
+extern const Substitution kRustSubstitutionRustFlags;
+
+bool IsValidRustSubstitution(const Substitution* type);
+
+#endif  // TOOLS_GN_RUST_SUBSTITUTION_TYPE_H_
diff --git a/tools/gn/substitution_pattern_unittest.cc b/tools/gn/substitution_pattern_unittest.cc
index 59c057f..1a6498f 100644
--- a/tools/gn/substitution_pattern_unittest.cc
+++ b/tools/gn/substitution_pattern_unittest.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "tools/gn/substitution_pattern.h"
+
 #include "tools/gn/err.h"
+#include "tools/gn/rust_substitution_type.h"
 #include "util/test/test.h"
 
 TEST(SubstitutionPattern, ParseLiteral) {
@@ -47,3 +49,25 @@
   EXPECT_FALSE(pattern.Parse("{{source{{source}}", nullptr, &err));
   EXPECT_TRUE(err.has_error());
 }
+
+TEST(SubstitutionPattern, ParseRust) {
+  SubstitutionPattern pattern;
+  Err err;
+  EXPECT_TRUE(pattern.Parse(
+      "AA{{rustflags}}{{rustenv}}BB{{crate_name}}{{rustdeps}}CC{{externs}}",
+      nullptr, &err));
+  EXPECT_FALSE(err.has_error());
+  ASSERT_EQ(8u, pattern.ranges().size());
+
+  EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[0].type);
+  EXPECT_EQ("AA", pattern.ranges()[0].literal);
+  EXPECT_EQ(&kRustSubstitutionRustFlags, pattern.ranges()[1].type);
+  EXPECT_EQ(&kRustSubstitutionRustEnv, pattern.ranges()[2].type);
+  EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[3].type);
+  EXPECT_EQ("BB", pattern.ranges()[3].literal);
+  EXPECT_EQ(&kRustSubstitutionCrateName, pattern.ranges()[4].type);
+  EXPECT_EQ(&kRustSubstitutionRustDeps, pattern.ranges()[5].type);
+  EXPECT_EQ(&SubstitutionLiteral, pattern.ranges()[6].type);
+  EXPECT_EQ("CC", pattern.ranges()[6].literal);
+  EXPECT_EQ(&kRustSubstitutionExterns, pattern.ranges()[7].type);
+}
\ No newline at end of file
diff --git a/tools/gn/substitution_type.cc b/tools/gn/substitution_type.cc
index ae680c9..6972beb 100644
--- a/tools/gn/substitution_type.cc
+++ b/tools/gn/substitution_type.cc
@@ -9,9 +9,10 @@
 
 #include "tools/gn/c_substitution_type.h"
 #include "tools/gn/err.h"
+#include "tools/gn/rust_substitution_type.h"
 
-const std::vector<SubstitutionTypes*> AllSubstitutions = {&GeneralSubstitutions,
-                                                          &CSubstitutions};
+const std::vector<SubstitutionTypes*> AllSubstitutions = {
+    &GeneralSubstitutions, &CSubstitutions, &RustSubstitutions};
 
 const SubstitutionTypes GeneralSubstitutions = {
     &SubstitutionLiteral,