Merge pull request #18 from google:ssbr-patch-1

PiperOrigin-RevId: 825256803
Change-Id: I2b7a27195f025f2f7d85a5bf56fcda32374d57af
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 7424520..80706d9 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -1,4 +1,7 @@
-name: Rust
+# Part of the Crubit project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+name: Cargo
 
 on:
   push:
@@ -18,5 +21,3 @@
     - uses: actions/checkout@v4
     - name: Build
       run: cargo build --verbose --bin cc_bindings_from_rs
-    # - name: Run tests
-    #   run: cargo test --verbose
diff --git a/support/rs_std/char.h b/support/rs_std/char.h
index 47577ae..b2b4e84 100644
--- a/support/rs_std/char.h
+++ b/support/rs_std/char.h
@@ -9,6 +9,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <optional>
+#include <type_traits>
 
 #include "absl/base/optimization.h"
 #include "absl/types/span.h"
@@ -44,10 +45,22 @@
   // for C++ which argues that zero-initialization may mitigate 10% of exploits.
   constexpr char_() noexcept = default;
 
-  // Constant-time implicit constructor which converts a Unicode scalar value
-  // `uint32_t` into an `rs_std::char_`. This function performs compile-time
-  // validation that the `uint32_t` is a valid Unicode scalar value.
-  explicit consteval char_(char32_t c) noexcept : value_(c) {
+  // Constant-time implicit constructor which converts a character
+  // literal into an `rs_std::char_`. This function performs compile-time
+  // validation that the argument is a valid Unicode scalar value.
+  //
+  // Note: this constructor is templated in order to ensure that implicit
+  // conversions from `int` values are not applied.
+  template <typename Char, typename CharNoCv = std::remove_cvref_t<Char>,
+            typename = std::enable_if_t<std::is_same_v<CharNoCv, char> ||
+                                        std::is_same_v<CharNoCv, char8_t> ||
+                                        std::is_same_v<CharNoCv, char16_t> ||
+                                        std::is_same_v<CharNoCv, char32_t>>>
+  consteval char_(  // NOLINT(google-explicit-constructor)
+                    // Style waiver for implicit conversions granted in
+                    // cl/825200658.
+      Char c) noexcept
+      : value_(c) {
     if (!IsValidCodePoint(c)) {
       internal::CharArgumentMustBeUnicodeCodePoint();
     }
diff --git a/support/rs_std/str_ref.h b/support/rs_std/str_ref.h
index 3b7e930..7f24653 100644
--- a/support/rs_std/str_ref.h
+++ b/support/rs_std/str_ref.h
@@ -66,18 +66,21 @@
     return StrRef(UnsafePromiseUtf8(), string_view);
   }
 
-  // consteval implict conversion from `const char*` so that string
+  // consteval implicit conversion from `const char*` so that string
   // literals can be used as `StrRef` arguments while still requiring runtime
   // UTF8 validation to be explicit.
-  //
-  // Note: consider this constructor for an implicit conversion waiver.
-  explicit consteval StrRef(const char* absl_nonnull char_ptr) noexcept
+  consteval StrRef(  // NOLINT(google-explicit-constructor)
+                     // Style waiver for implicit conversions granted in
+                     // cl/825200658.
+      const char* absl_nonnull char_ptr) noexcept
       : StrRef(absl::string_view(char_ptr)) {}
 
-  // consteval implict conversion from `absl::string_view`.
-  //
-  // Note: consider this constructor for an implicit conversion waiver.
-  explicit consteval StrRef(absl::string_view string_view) noexcept : slice_() {
+  // consteval implicit conversion from `absl::string_view`.
+  consteval StrRef(  // NOLINT(google-explicit-constructor)
+                     // Style waiver for implicit conversions granted in
+                     // cl/825200658.
+      absl::string_view string_view) noexcept
+      : slice_() {
     if (!string_view.empty()) {
       // We cannot use `static_assert` because C++ does not treat arguments
       // to `consteval` functions as constants.
@@ -90,8 +93,11 @@
     }
   }
 
-  // Note: consider conversion operator for an implicit conversion waiver.
-  explicit constexpr operator absl::string_view() const noexcept {
+  constexpr
+  operator absl::string_view()  // NOLINT(google-explicit-constructor)
+                                // Style waiver for implicit
+                                // conversions granted in cl/825200658.
+      const noexcept {
     return absl::string_view(slice_.data(), slice_.size());
   }
 
@@ -145,6 +151,14 @@
   return rhs == lhs;
 }
 
+constexpr bool operator==(StrRef lhs, const char* rhs) noexcept {
+  return lhs.to_string_view() == absl::string_view(rhs);
+}
+
+constexpr bool operator==(const char* lhs, StrRef rhs) noexcept {
+  return rhs == lhs;
+}
+
 constexpr auto operator<=>(StrRef lhs, StrRef rhs) noexcept {
   return lhs.to_string_view() <=> rhs.to_string_view();
 }
@@ -157,6 +171,14 @@
   return lhs <=> rhs.to_string_view();
 }
 
+constexpr auto operator<=>(StrRef lhs, const char* rhs) noexcept {
+  return lhs.to_string_view() <=> absl::string_view(rhs);
+}
+
+constexpr auto operator<=>(const char* lhs, StrRef rhs) noexcept {
+  return absl::string_view(lhs) <=> rhs.to_string_view();
+}
+
 }  // namespace rs_std
 
 namespace crubit::internal {
diff --git a/support/rs_std/str_ref_test.cc b/support/rs_std/str_ref_test.cc
index 5d04634..361d50f 100644
--- a/support/rs_std/str_ref_test.cc
+++ b/support/rs_std/str_ref_test.cc
@@ -64,20 +64,20 @@
   static constexpr absl::string_view kStr = "12345";
   static constexpr absl::string_view kStrCopy = "12345";
 
-  static constexpr StrRef kStrRef = StrRef(kStr);
+  static constexpr StrRef kStrRef = kStr;
   static constexpr StrRef kStrRefCopy = kStrRef;
-  static constexpr StrRef kStrRef2 = StrRef(kStrCopy);
+  static constexpr StrRef kStrRef2 = kStrCopy;
 
   static_assert(kStrRef == kStrRef);
   static_assert(kStrRef == kStrRefCopy);
   static_assert(kStrRef == kStrRef2);
 
   static constexpr StrRef kStrRef_prefix =
-      StrRef(absl::string_view(kStr.data(), kStr.size() - 1));
+      absl::string_view(kStr.data(), kStr.size() - 1);
   static constexpr StrRef kStrRef_suffix =
-      StrRef(absl::string_view(kStr.data() + 1, kStr.size() - 1));
+      absl::string_view(kStr.data() + 1, kStr.size() - 1);
   static constexpr StrRef kStrRef_infix =
-      StrRef(absl::string_view(kStr.data() + 1, kStr.size() - 2));
+      absl::string_view(kStr.data() + 1, kStr.size() - 2);
 
   EXPECT_GT(kStrRef, kStrRef_prefix);
   EXPECT_LT(kStrRef, kStrRef_suffix);
@@ -86,7 +86,7 @@
 
 TEST(StrTest, FromAndTo) {
   static constexpr absl::string_view kStr = "12345";
-  static constexpr StrRef kStrRef = StrRef(kStr);
+  static constexpr StrRef kStrRef = kStr;
   EXPECT_EQ(kStr, kStrRef);
 }
 
@@ -101,7 +101,7 @@
 // `StrRef` is correct.
 TEST(StrTest, Layout) {
   static constexpr absl::string_view kStr = "foo";
-  const StrRef s = StrRef(kStr);
+  const StrRef s = kStr;
   const auto fields = std::bit_cast<StrRefFields>(s);
   EXPECT_EQ(fields.ptr, kStr.data());
   EXPECT_EQ(fields.size, kStr.size());
@@ -109,7 +109,7 @@
 
 TEST(StrTest, Empty) {
   static constexpr const char* kEmpty = "";
-  const StrRef empty = StrRef(absl::string_view(kEmpty, 0));
+  const StrRef empty = absl::string_view(kEmpty, 0);
   static constexpr StrRef default_constructed;
   EXPECT_EQ(empty, default_constructed);
 
@@ -125,7 +125,7 @@
 
 TEST(StrTest, StrCat) {
   static constexpr absl::string_view kStr = "12345";
-  static constexpr StrRef kStrRef = StrRef("12345");
+  static constexpr StrRef kStrRef = "12345";
   EXPECT_EQ(absl::StrCat(kStrRef), kStr);
 }
 
@@ -144,7 +144,7 @@
 
 TEST(ImplicitConversionTest, FromConstCharPtr) {
   static constexpr const char* kConstCharPtr = "12";
-  static constexpr StrRef kStrRef = StrRef(kConstCharPtr);
+  static constexpr StrRef kStrRef = kConstCharPtr;
   EXPECT_EQ(kStrRef, "12");
 }