Add more implicit conversions from containers to rs_std::SliceRef

This CL tries to achieve it by delegating to `absl::Span`'s constructors.

PiperOrigin-RevId: 663041577
Change-Id: I9db734cf639194bdacb7f0dd4833df5351a03ba0
diff --git a/support/rs_std/BUILD b/support/rs_std/BUILD
index 5bc0537..9f3b650 100644
--- a/support/rs_std/BUILD
+++ b/support/rs_std/BUILD
@@ -48,6 +48,7 @@
     # and/or exact absl/base/options.h).
     deps = [
         "//support/internal:bindings_support",
+        "@abseil-cpp//absl/base",
         "@abseil-cpp//absl/base:core_headers",
         "@abseil-cpp//absl/types:span",
     ],
diff --git a/support/rs_std/slice_ref.h b/support/rs_std/slice_ref.h
index 47cfe1b..ca0414e 100644
--- a/support/rs_std/slice_ref.h
+++ b/support/rs_std/slice_ref.h
@@ -5,11 +5,14 @@
 #ifndef THIRD_PARTY_CRUBIT_SUPPORT_RS_STD_SLICEREF_H_
 #define THIRD_PARTY_CRUBIT_SUPPORT_RS_STD_SLICEREF_H_
 
+#include <concepts>
 #include <cstddef>
 #include <cstdint>
 #include <span>  // NOLINT(build/c++20); <internal link>
+#include <type_traits>
 
 #include "absl/base/attributes.h"
+#include "absl/base/casts.h"
 #include "absl/types/span.h"
 #include "support/internal/attribute_macros.h"
 
@@ -40,6 +43,24 @@
                           : reinterpret_cast<uintptr_t>(span.data())),
         size_(span.size()) {}
 
+  // Re-use implicit conversions to `absl::Span`. Prevent a delegation circle
+  // by excluding `absl::Span<T>` as the converted type.
+  template <typename Container>
+    requires(std::convertible_to<Container &&, absl::Span<T>> &&
+             !std::is_same_v<Container, absl::Span<T>>)
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  SliceRef(Container&& container) noexcept
+      : SliceRef(absl::implicit_cast<absl::Span<T>>(
+            std::forward<Container>(container))) {}
+
+  // Also mirror explicit conversions from `absl::Span`.
+  template <typename Container>
+    requires(std::constructible_from<absl::Span<T>, Container &&> &&
+             !std::convertible_to<Container &&, absl::Span<T>> &&
+             !std::is_same_v<Container, absl::Span<T>>)
+  explicit SliceRef(Container&& container) noexcept
+      : SliceRef(absl::Span<T>(std::forward<Container>(container))) {}
+
   // NOLINTNEXTLINE(google-explicit-constructor)
   constexpr operator std::span<T>() const {
     return std::span<T>(size_ > 0 ? static_cast<T*>(ptr_) : nullptr, size_);
diff --git a/support/rs_std/slice_ref_test.cc b/support/rs_std/slice_ref_test.cc
index dbdcd5e..68ad1ca 100644
--- a/support/rs_std/slice_ref_test.cc
+++ b/support/rs_std/slice_ref_test.cc
@@ -19,6 +19,7 @@
 #include "absl/types/span.h"
 
 namespace {
+using ::testing::ElementsAre;
 using ::testing::IsNull;
 using ::testing::Not;
 
@@ -75,19 +76,19 @@
   static constexpr std::array<uint8_t, 5> kArr = {1, 2, 3, 4, 5};
   static constexpr std::array<uint8_t, 5> kArrCopy = {1, 2, 3, 4, 5};
 
-  const rs_std::SliceRef<const uint8_t> s1(kArr);
+  const rs_std::SliceRef<const uint8_t> s1 = kArr;
   const rs_std::SliceRef<const uint8_t> s1_copy = s1;
-  const rs_std::SliceRef<const uint8_t> s2(kArrCopy);
+  const rs_std::SliceRef<const uint8_t> s2 = kArrCopy;
 
   EXPECT_EQ(s1.to_span(), s1.to_span());
   EXPECT_EQ(s1.to_span(), s1_copy.to_span());
   EXPECT_EQ(s1.to_span(), s2.to_span());
-  const rs_std::SliceRef<const uint8_t> s1_prefix(
-      absl::MakeSpan(kArr.data(), kArr.size() - 1));
-  const rs_std::SliceRef<const uint8_t> s1_suffix(
-      absl::MakeSpan(kArr.data() + 1, kArr.size() - 1));
-  const rs_std::SliceRef<const uint8_t> s1_infix(
-      absl::MakeSpan(kArr.data() + 1, kArr.size() - 2));
+  const rs_std::SliceRef<const uint8_t> s1_prefix =
+      absl::MakeSpan(kArr.data(), kArr.size() - 1);
+  const rs_std::SliceRef<const uint8_t> s1_suffix =
+      absl::MakeSpan(kArr.data() + 1, kArr.size() - 1);
+  const rs_std::SliceRef<const uint8_t> s1_infix =
+      absl::MakeSpan(kArr.data() + 1, kArr.size() - 2);
 
   EXPECT_NE(s1.to_span(), s1_prefix.to_span());
   EXPECT_NE(s1.to_span(), s1_suffix.to_span());
@@ -96,7 +97,7 @@
 
 TEST(SliceTest, FromAndTo) {
   static constexpr std::array<uint8_t, 5> kArr = {1, 2, 3, 4, 5};
-  const rs_std::SliceRef<const uint8_t> s(kArr);
+  const rs_std::SliceRef<const uint8_t> s = kArr;
   EXPECT_EQ(absl::Span<const uint8_t>(kArr), s.to_span());
 }
 
@@ -111,7 +112,7 @@
 // `SliceRef` is correct.
 TEST(SliceTest, Layout) {
   static constexpr std::array<uint8_t, 5> kArr = {2, 3, 5};
-  const rs_std::SliceRef<const uint8_t> s(kArr);
+  const rs_std::SliceRef<const uint8_t> s = kArr;
   const auto fields = std::bit_cast<SliceRefFields>(s);
   EXPECT_EQ(fields.ptr, kArr.data());
   EXPECT_EQ(fields.size, kArr.size());
@@ -119,7 +120,7 @@
 
 TEST(SliceTest, Empty) {
   static constexpr uint8_t kEmpty[] = {};
-  const rs_std::SliceRef<const uint8_t> empty(absl::MakeSpan(kEmpty, 0));
+  const rs_std::SliceRef<const uint8_t> empty = absl::MakeSpan(kEmpty, 0);
   static constexpr rs_std::SliceRef<const uint8_t> default_constructed;
   EXPECT_EQ(empty.to_span(), default_constructed.to_span());
 
@@ -133,8 +134,41 @@
   EXPECT_EQ(empty.size(), 0);
 }
 
+TEST(ImplicitConversionTest, MutableFromVector) {
+  std::vector<int> vec = {1, 2, 3};
+  // Mirroring `absl::Span`, there is no implicit conversion from mutable
+  // containers.
+  static_assert(!std::convertible_to<std::vector<int>&, rs_std::SliceRef<int>>);
+  // Explicit conversion works.
+  const rs_std::SliceRef<int> from_vec(vec);
+  EXPECT_THAT(from_vec.to_span(), ElementsAre(1, 2, 3));
+}
+
+TEST(ImplicitConversionTest, FromConstVector) {
+  const std::vector<int> vec = {1, 2, 3};
+  const rs_std::SliceRef<const int> from_vec = vec;
+  EXPECT_THAT(from_vec.to_span(), ElementsAre(1, 2, 3));
+}
+
+TEST(ImplicitConversionTest, FromArray) {
+  std::array<int, 2> arr = {1, 2};
+  // Mirroring `absl::Span`, there is no implicit conversion from mutable
+  // containers.
+  static_assert(
+      !std::convertible_to<std::array<int, 2>&, rs_std::SliceRef<int>>);
+  // Explicit conversion works.
+  const rs_std::SliceRef<int> from_arr(arr);
+  EXPECT_THAT(from_arr.to_span(), ElementsAre(1, 2));
+}
+
+TEST(ImplicitConversionTest, FromConstArray) {
+  static constexpr std::array<int, 2> arr = {1, 2};
+  const rs_std::SliceRef<const int> from_arr = arr;
+  EXPECT_THAT(from_arr.to_span(), ElementsAre(1, 2));
+}
+
 void Fuzzer(std::vector<uint8_t> data) {
-  const rs_std::SliceRef<const uint8_t> s(data);
+  const rs_std::SliceRef<const uint8_t> s = data;
   EXPECT_EQ(absl::Span<const uint8_t>(data), s.to_span());
   const std::vector<uint8_t> data_copy(s.data(), s.data() + s.size());
   EXPECT_EQ(data, data_copy);