Introduce submessage view accessors for arbitrary depths

Before this CL, we weren't generating view accessors for messages with depth > 1.
We weren't getting to message::GetterForViewOrMut because we were detecting FieldDescriptor::TYPE_MESSAGE and bailing out.

That check has now been expunged, and we now properly emit the right view, even for messages embedded within messages.

Added tests for:
- another level of submsg access depth
- accessing a message declared outside of the current message (that is, not a direct nested message within the same message)
- accessing the accessor of the accessor of the accessor of a recursively defined message

PiperOrigin-RevId: 588460599
diff --git a/rust/test/nested.proto b/rust/test/nested.proto
index e6d4f29..59aee22 100644
--- a/rust/test/nested.proto
+++ b/rust/test/nested.proto
@@ -11,6 +11,10 @@
 
 message Outer {
   message Inner {
+    message InnerSubMsg {
+      optional bool flag = 1;
+    }
+
     optional double double = 1;
     optional float float = 2;
     optional int32 int32 = 3;
@@ -26,6 +30,7 @@
     optional bool bool = 13;
     optional string string = 14;
     optional bytes bytes = 15;
+    optional InnerSubMsg innersubmsg = 16;
 
     message SuperInner {
       message DuperInner {
@@ -40,4 +45,15 @@
   optional Inner inner = 1;
   optional .nest.Outer.Inner.SuperInner.DuperInner.EvenMoreInner
       .CantBelieveItsSoInner deep = 2;
+
+  optional NotInside notinside = 3;
+}
+
+message NotInside {
+  optional int32 num = 1;
+}
+
+message Recursive {
+  optional Recursive rec = 1;
+  optional int32 num = 2;
 }
diff --git a/rust/test/shared/simple_nested_test.rs b/rust/test/shared/simple_nested_test.rs
index cd87799..a13d4b5 100644
--- a/rust/test/shared/simple_nested_test.rs
+++ b/rust/test/shared/simple_nested_test.rs
@@ -39,6 +39,7 @@
     assert_that!(inner_msg.bool(), eq(false));
     assert_that!(*inner_msg.string().as_bytes(), empty());
     assert_that!(*inner_msg.bytes(), empty());
+    assert_that!(inner_msg.innersubmsg().flag(), eq(false));
 }
 
 #[test]
@@ -96,3 +97,20 @@
     );
     // TODO: add mutation tests for strings and bytes
 }
+
+#[test]
+fn test_msg_from_outside() {
+    // let's make sure that we're not just working for messages nested inside
+    // messages, messages from without and within should work
+    let outer = nested_proto::nest::Outer::new();
+    assert_that!(outer.notinside().num(), eq(0));
+}
+
+#[test]
+fn test_recursive_msg() {
+    let rec = nested_proto::nest::Recursive::new();
+    assert_that!(rec.num(), eq(0));
+    assert_that!(rec.rec().num(), eq(0));
+    assert_that!(rec.rec().rec().num(), eq(0)); // turtles all the way down...
+    assert_that!(rec.rec().rec().rec().num(), eq(0)); // ... ad infinitum
+}
diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc
index 6bc142f..9cc3523 100644
--- a/src/google/protobuf/compiler/rust/message.cc
+++ b/src/google/protobuf/compiler/rust/message.cc
@@ -9,7 +9,7 @@
 
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
-#include "absl/strings/str_cat.h"
+#include "absl/strings/match.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/compiler/cpp/helpers.h"
 #include "google/protobuf/compiler/cpp/names.h"
@@ -173,8 +173,50 @@
   // If we're dealing with a Mut, the getter must be supplied
   // self.inner.msg() whereas a View has to be supplied self.msg
   auto self = is_mut ? "self.inner.msg()" : "self.msg";
-  auto rsType = PrimitiveRsTypeName(field.desc());
+  if (fieldType == FieldDescriptor::TYPE_MESSAGE) {
+    Context<Descriptor> d = field.WithDesc(field.desc().message_type());
+    auto prefix = "crate::" + GetCrateRelativeQualifiedPath(d);
+    // TODO: investigate imports breaking submsg accessors
+    if (absl::StrContains(prefix, "import")) {
+      return;
+    }
+    field.Emit(
+        {
+            {"prefix", prefix},
+            {"field", fieldName},
+            {"self", self},
+            {"getter_thunk", getter_thunk},
+            // TODO: dedupe with singular_message.cc
+            {
+                "view_body",
+                [&] {
+                  if (field.is_upb()) {
+                    field.Emit({}, R"rs(
+                      let submsg = unsafe { $getter_thunk$($self$) };
+                      match submsg {
+                        None => $prefix$View::new($pbi$::Private,
+                          $pbr$::ScratchSpace::zeroed_block($pbi$::Private)),
+                        Some(field) => $prefix$View::new($pbi$::Private, field),
+                      }
+                )rs");
+                  } else {
+                    field.Emit({}, R"rs(
+                      let submsg = unsafe { $getter_thunk$($self$) };
+                      $prefix$View::new($pbi$::Private, submsg)
+                )rs");
+                  }
+                },
+            },
+        },
+        R"rs(
+              pub fn r#$field$(&self) -> $prefix$View {
+                $view_body$
+              }
+            )rs");
+    return;
+  }
 
+  auto rsType = PrimitiveRsTypeName(field.desc());
   if (fieldType == FieldDescriptor::TYPE_STRING) {
     field.Emit(
         {
@@ -250,8 +292,7 @@
     // TODO - add cord support
     if (field.desc().options().has_ctype()) continue;
     // TODO
-    if (field.desc().type() == FieldDescriptor::TYPE_MESSAGE ||
-        field.desc().type() == FieldDescriptor::TYPE_ENUM ||
+    if (field.desc().type() == FieldDescriptor::TYPE_ENUM ||
         field.desc().type() == FieldDescriptor::TYPE_GROUP)
       continue;
     GetterForViewOrMut(field, is_mut);