Add initial end-to-end test directory structure.

This turns out to be quite of a yak shave to be able to perfectly test both kernels without having to pass extra Blaze flags.

PiperOrigin-RevId: 521850709
diff --git a/.github/workflows/test_rust.yml b/.github/workflows/test_rust.yml
index 8f9b16a..3edec3e 100644
--- a/.github/workflows/test_rust.yml
+++ b/.github/workflows/test_rust.yml
@@ -24,6 +24,7 @@
           credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
           bazel-cache: rust_linux
           bazel: |
-            test //rust:protobuf_test //rust/cpp_kernel:cpp_test \
+            test //rust:protobuf_upb_test //rust:protobuf_cpp_test \
+              //rust/upb_kernel:upb_test //rust/cpp_kernel:cpp_test \
               //rust/test/rust_proto_library_unit_test:rust_upb_aspect_test \
               //rust/upb_kernel:upb_test //src/google/protobuf/compiler/rust/...
\ No newline at end of file
diff --git a/rust/BUILD b/rust/BUILD
index 4ea1156..247fa67 100644
--- a/rust/BUILD
+++ b/rust/BUILD
@@ -11,29 +11,56 @@
 
 rust_library(
     name = "protobuf",
-    srcs = ["lib.rs"],
+    srcs = ["protobuf.rs"],
     rustc_flags = select({
         ":use_upb_kernel": ["--cfg=upb_kernel"],
         "//conditions:default": ["--cfg=cpp_kernel"],
     }),
     deps = select({
-        ":use_upb_kernel": ["//rust/upb_kernel:upb"],
-        "//conditions:default": ["//rust/cpp_kernel:cpp"],
+        ":use_upb_kernel": [":protobuf_upb"],
+        "//conditions:default": [":protobuf_cpp"],
     }),
 )
 
+rust_library(
+    name = "protobuf_upb",
+    srcs = ["shared.rs"],
+    rustc_flags = ["--cfg=upb_kernel"],
+    deps = ["//rust/upb_kernel:upb"],
+)
+
 rust_test(
-    name = "protobuf_test",
-    crate = ":protobuf",
-    rustc_flags = select({
-        ":use_upb_kernel": ["--cfg=upb_kernel"],
-        "//conditions:default": ["--cfg=cpp_kernel"],
-    }),
+    name = "protobuf_upb_test",
+    crate = ":protobuf_upb",
+    rustc_flags = ["--cfg=upb_kernel"],
     tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+        "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
+        "notsan",
         # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
         "nomsan",
+    ],
+)
+
+rust_library(
+    name = "protobuf_cpp",
+    srcs = ["shared.rs"],
+    rustc_flags = ["--cfg=cpp_kernel"],
+    deps = ["//rust/cpp_kernel:cpp"],
+)
+
+rust_test(
+    name = "protobuf_cpp_test",
+    crate = ":protobuf_cpp",
+    rustc_flags = ["--cfg=cpp_kernel"],
+    tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
         "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
         "notsan",
+        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
+        "nomsan",
     ],
 )
 
@@ -42,7 +69,7 @@
     name = "proto_rust_upb_toolchain",
     command_line = "--rust_out=experimental-codegen=enabled,kernel=upb:$(OUT)",
     progress_message = "Generating Rust proto_library %{label}",
-    runtime = ":protobuf",
+    runtime = ":protobuf_upb",
     visibility = ["//visibility:public"],
 )
 
@@ -50,7 +77,7 @@
     name = "proto_rust_cpp_toolchain",
     command_line = "--rust_out=experimental-codegen=enabled,kernel=cpp:$(OUT)",
     progress_message = "Generating Rust proto_library %{label}",
-    runtime = ":protobuf",
+    runtime = ":protobuf_cpp",
     visibility = ["//visibility:public"],
 )
 
diff --git a/rust/protobuf.rs b/rust/protobuf.rs
new file mode 100644
index 0000000..9965375
--- /dev/null
+++ b/rust/protobuf.rs
@@ -0,0 +1,46 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2023 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//! Rust Protobuf Runtime
+//!
+//! This file forwards to the kernel specific implementation. Rust Protobuf
+//! gencode actually depends directly on kernel specific crates. The only reason
+//! this crate exists is to be able to use `protobuf` as a crate name for both
+//! cpp and upb kernels from user code.
+
+#[cfg(cpp_kernel)]
+pub use protobuf_cpp::__runtime;
+#[cfg(cpp_kernel)]
+pub use protobuf_cpp::*;
+
+#[cfg(upb_kernel)]
+pub use protobuf_upb::__runtime;
+#[cfg(upb_kernel)]
+pub use protobuf_upb::*;
diff --git a/rust/lib.rs b/rust/shared.rs
similarity index 94%
rename from rust/lib.rs
rename to rust/shared.rs
index ebe3659..e5c499d 100644
--- a/rust/lib.rs
+++ b/rust/shared.rs
@@ -28,7 +28,10 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-//! Rust Protobuf Runtime
+//! Kernel-agnostic logic for the Rust Protobuf Runtime.
+//!
+//! For kernel-specific logic this crate delegates to the respective __runtime
+//! crate.
 
 #[cfg(cpp_kernel)]
 pub extern crate cpp as __runtime;
diff --git a/rust/test/BUILD b/rust/test/BUILD
index 55dfeea..037c7c8 100644
--- a/rust/test/BUILD
+++ b/rust/test/BUILD
@@ -1,26 +1,40 @@
-load("//rust:defs.bzl", "rust_proto_library")
-load("@rules_rust//rust:defs.bzl", "rust_test")
+load("@rules_cc//cc:defs.bzl", "cc_proto_library")
+load(
+    "//rust:defs.bzl",
+    "rust_cc_proto_library",
+    "rust_proto_library",
+    "rust_upb_proto_library",
+)
+
+UNITTEST_PROTO_TARGET = (
+    "//src/google/protobuf:test_protos"
+)
 
 rust_proto_library(
     name = "unittest_rust_proto",
     testonly = True,
-    deps = [
-        "//src/google/protobuf:test_protos",
-    ],
+    visibility = ["//rust/test/shared:__subpackages__"],
+    deps = [UNITTEST_PROTO_TARGET],
 )
 
-rust_test(
-    name = "unittest_proto_test",
-    srcs = ["unittest_proto_test.rs"],
-    # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
-    tags = [
-        "not_build:arm",
-        # TODO(b/225892643): Enable once we use Blaze-bootstrapped Rust toolchain.
-        "notsan",
-        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
-        "nomsan",
+rust_upb_proto_library(
+    name = "unittest_upb_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/shared:__subpackages__",
+        "//rust/test/upb:__subpackages__",
     ],
-    deps = [":unittest_rust_proto"],
+    deps = [UNITTEST_PROTO_TARGET],
+)
+
+rust_cc_proto_library(
+    name = "unittest_cc_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/cpp:__subpackages__",
+        "//rust/test/shared:__subpackages__",
+    ],
+    deps = [":unittest_cc_proto"],
 )
 
 proto_library(
@@ -30,34 +44,60 @@
 
 proto_library(
     name = "child_proto",
+    testonly = True,
     srcs = ["child.proto"],
     exports = [":parent_proto"],
     deps = [":parent_proto"],
 )
 
-rust_proto_library(
-    name = "parent_rust_proto",
+rust_upb_proto_library(
+    name = "parent_upb_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/shared:__subpackages__",
+        "//rust/test/upb:__subpackages__",
+    ],
     deps = [":parent_proto"],
 )
 
-rust_proto_library(
-    name = "child_rust_proto",
+rust_upb_proto_library(
+    name = "child_upb_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/shared:__subpackages__",
+        "//rust/test/upb:__subpackages__",
+    ],
     deps = [":child_proto"],
 )
 
-rust_test(
-    name = "child_parent_test",
-    srcs = ["child_parent_test.rs"],
-    # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
-    tags = [
-        "not_build:arm",
-        # TODO(b/225892643): Enable once we use Blaze-bootstrapped Rust toolchain.
-        "notsan",
-        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
-        "nomsan",
+cc_proto_library(
+    name = "parent_cc_proto",
+    testonly = True,
+    deps = [":parent_proto"],
+)
+
+cc_proto_library(
+    name = "child_cc_proto",
+    testonly = True,
+    deps = [":child_proto"],
+)
+
+rust_cc_proto_library(
+    name = "parent_cc_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/cpp:__subpackages__",
+        "//rust/test/shared:__subpackages__",
     ],
-    deps = [
-        ":child_rust_proto",
-        ":parent_rust_proto",
+    deps = [":parent_cc_proto"],
+)
+
+rust_cc_proto_library(
+    name = "child_cc_rust_proto",
+    testonly = True,
+    visibility = [
+        "//rust/test/cpp:__subpackages__",
+        "//rust/test/shared:__subpackages__",
     ],
+    deps = [":child_cc_proto"],
 )
diff --git a/rust/test/cpp/BUILD b/rust/test/cpp/BUILD
new file mode 100644
index 0000000..91782bf
--- /dev/null
+++ b/rust/test/cpp/BUILD
@@ -0,0 +1,11 @@
+# Tests specific to cpp kernel.
+#
+# Only add tests that are cpp kernel specific and it is not possible to make them work for upb (
+# for example tests exercising ABI compatibility with C++ Protobuf API).
+#
+# All the tests under this package should ignore
+# `//rust:rust_proto_library_kernel` flag and should always select `cpp`.
+#
+# To do that use:
+# * `rust_cc_proto_library` instead of `rust_proto_library`.
+# * `//rust:protobuf_cpp` instead of `//rust:protobuf``.
diff --git a/rust/test/shared/BUILD b/rust/test/shared/BUILD
new file mode 100644
index 0000000..5e9591f
--- /dev/null
+++ b/rust/test/shared/BUILD
@@ -0,0 +1,79 @@
+# Tests that are exercising and should pass with both kernels.
+#
+# All the tests under this package should ignore
+# `//rust:rust_proto_library_kernel` flag and should always cover both
+# kernels.
+#
+# To do that:
+# * Declare 2 rust_test targets and share the same sources from both.
+# * First copy will only depend on `rust_cc_proto_library` Rust proto targets, and if needed will
+#   only depend on `//rust:protobuf_cpp.
+# * Second copy will only depend on `rust_upb_proto_library` Rust proto targets, and if needed will
+#   only depend on `//rust:protobuf_upb
+#
+# Once we have a couple of these tests we will investigate ways to remove boilerplate (for example
+# by introducing a build macro that registers 2 rust_test targets).
+
+load("@rules_rust//rust:defs.bzl", "rust_test")
+
+rust_test(
+    name = "unittest_proto_upb_test",
+    srcs = ["unittest_proto_test.rs"],
+    tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+        "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
+        "notsan",
+        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
+        "nomsan",
+    ],
+    deps = ["//rust/test:unittest_upb_rust_proto"],
+)
+
+rust_test(
+    name = "unittest_proto_cpp_test",
+    srcs = ["unittest_proto_test.rs"],
+    tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+        "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
+        "notsan",
+        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
+        "nomsan",
+    ],
+    deps = ["//rust/test:unittest_cc_rust_proto"],
+)
+
+rust_test(
+    name = "child_parent_upb_test",
+    srcs = ["child_parent_test.rs"],
+    tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+        "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
+        "notsan",
+        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
+        "nomsan",
+    ],
+    deps = [
+        "//rust/test:child_upb_rust_proto",
+        "//rust/test:parent_upb_rust_proto",
+    ],
+)
+
+rust_test(
+    name = "child_parent_cpp_test",
+    srcs = ["child_parent_test.rs"],
+    tags = [
+        # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+        "not_build:arm",
+        # TODO(b/243126140): Enable tsan once we support sanitizers with Rust.
+        "notsan",
+        # TODO(b/243126140): Enable msan once we support sanitizers with Rust.
+        "nomsan",
+    ],
+    deps = [
+        "//rust/test:child_cc_rust_proto",
+        "//rust/test:parent_cc_rust_proto",
+    ],
+)
diff --git a/rust/test/child_parent_test.rs b/rust/test/shared/child_parent_test.rs
similarity index 100%
rename from rust/test/child_parent_test.rs
rename to rust/test/shared/child_parent_test.rs
diff --git a/rust/test/unittest_proto_test.rs b/rust/test/shared/unittest_proto_test.rs
similarity index 100%
rename from rust/test/unittest_proto_test.rs
rename to rust/test/shared/unittest_proto_test.rs
diff --git a/rust/test/upb/BUILD b/rust/test/upb/BUILD
new file mode 100644
index 0000000..33f2962
--- /dev/null
+++ b/rust/test/upb/BUILD
@@ -0,0 +1,11 @@
+# Tests specific to upb kernel.
+#
+# Only add tests that are cpp kernel specific and it is not possible to make them work for upb (
+# for example tests exercising ABI compatibility with other UPB-based Protobuf implementations).
+#
+# All the tests under this package should ignore
+# `//rust:rust_proto_library_kernel` flag and should always select `upb`.
+#
+# To do that use:
+# * `rust_upb_proto_library` instead of `rust_proto_library`.
+# * `//rust:protobuf_upb` instead of `//rust:protobuf``.
diff --git a/rust/upb_kernel/BUILD b/rust/upb_kernel/BUILD
index 8389b80..1d362c4 100644
--- a/rust/upb_kernel/BUILD
+++ b/rust/upb_kernel/BUILD
@@ -5,7 +5,10 @@
 rust_library(
     name = "upb",
     srcs = ["upb.rs"],
-    visibility = ["//src/google/protobuf:__subpackages__"],
+    visibility = [
+        "//src/google/protobuf:__subpackages__",
+        "//rust:__subpackages__",
+    ],
     deps = [":upb_c_api"],
 )
 
diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc
index a92467a..5e6f755 100644
--- a/src/google/protobuf/compiler/rust/generator.cc
+++ b/src/google/protobuf/compiler/rust/generator.cc
@@ -173,6 +173,17 @@
   }
 }
 
+std::string GetKernelRustName(Kernel kernel) {
+  switch (kernel) {
+    case Kernel::kUpb:
+      return "upb";
+    case Kernel::kCpp:
+      return "cpp";
+  }
+  ABSL_LOG(FATAL) << "Unknown kernel type: ";
+  return "";
+}
+
 bool RustGenerator::Generate(const FileDescriptor* file,
                              const std::string& parameter,
                              GeneratorContext* generator_context,
@@ -201,8 +212,8 @@
       absl::StrCat(basename, GetFileExtensionForKernel(*kernel))));
 
   google::protobuf::io::Printer p(outfile.get());
-  p.Emit(R"rs(
-    extern crate protobuf as __pb;
+  p.Emit({{"kernel", GetKernelRustName(*kernel)}}, R"rs(
+    extern crate protobuf_$kernel$ as __pb;
     extern crate std as __std;
 
   )rs");