Introduce preliminary submessage_mut semantics

We've had access to views for submessages for a while:
If you hit some_message.submsg().some_int(), you'll get a view for that int.

Until now, there hasn't been a way to get some_message.submsg_mut(), so we introduce the mutational pathway here.

We haven't added fully-functioning mutation, but this is a step towards that goal.

subview was inaccurate, so I've refactored and renamed: { accessor_fns_for_views, accessor_fns_for_muts }.

PiperOrigin-RevId: 581984371
diff --git a/rust/cpp.rs b/rust/cpp.rs
index 7c4998f..d1f670b 100644
--- a/rust/cpp.rs
+++ b/rust/cpp.rs
@@ -171,6 +171,14 @@
         MutatorMessageRef { msg: msg.msg, _phantom: PhantomData }
     }
 
+    pub fn from_parent(
+        _private: Private,
+        _parent_msg: &'msg mut MessageInner,
+        message_field_ptr: RawMessage,
+    ) -> Self {
+        MutatorMessageRef { msg: message_field_ptr, _phantom: PhantomData }
+    }
+
     pub fn msg(&self) -> RawMessage {
         self.msg
     }
diff --git a/rust/test/nested.proto b/rust/test/nested.proto
index 80b0c61..6663a5a 100644
--- a/rust/test/nested.proto
+++ b/rust/test/nested.proto
@@ -11,8 +11,19 @@
 
 message Outer {
   message Inner {
-    optional int32 num = 1;
-    optional bool boolean = 2;
+    optional double double = 1;
+    optional float float = 2;
+    optional int32 int32 = 3;
+    optional int64 int64 = 4;
+    optional uint32 uint32 = 5;
+    optional uint64 uint64 = 6;
+    optional sint32 sint32 = 7;
+    optional sint64 sint64 = 8;
+    optional fixed32 fixed32 = 9;
+    optional fixed64 fixed64 = 10;
+    optional sfixed32 sfixed32 = 11;
+    optional sfixed64 sfixed64 = 12;
+    optional bool bool = 13;
 
     message SuperInner {
       message DuperInner {
diff --git a/rust/test/shared/BUILD b/rust/test/shared/BUILD
index b5864a3..06f5633 100644
--- a/rust/test/shared/BUILD
+++ b/rust/test/shared/BUILD
@@ -261,7 +261,10 @@
         # TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
         "not_build:arm",
     ],
-    deps = ["//rust/test:nested_cc_rust_proto"],
+    deps = [
+        "@crate_index//:googletest",
+        "//rust/test:nested_cc_rust_proto",
+    ],
 )
 
 rust_test(
@@ -271,7 +274,10 @@
         # TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
         "not_build:arm",
     ],
-    deps = ["//rust/test:nested_upb_rust_proto"],
+    deps = [
+        "@crate_index//:googletest",
+        "//rust/test:nested_upb_rust_proto",
+    ],
 )
 
 rust_test(
diff --git a/rust/test/shared/accessors_test.rs b/rust/test/shared/accessors_test.rs
index e5949ff..70c8cc0 100644
--- a/rust/test/shared/accessors_test.rs
+++ b/rust/test/shared/accessors_test.rs
@@ -667,11 +667,16 @@
 
 #[test]
 fn test_singular_msg_field() {
-    use crate::TestAllTypes_::NestedMessageView;
-    let msg = TestAllTypes::new();
-    // TODO: fetch the inner integer `bb`
-    // call should look like msg.optional_nested_message().bb()
-    let _msg: NestedMessageView = msg.optional_nested_message();
+    use crate::TestAllTypes_::{NestedMessageMut, NestedMessageView};
+
+    let mut msg = TestAllTypes::new();
+    let msg_view: NestedMessageView = msg.optional_nested_message();
+    // testing reading an int inside a view
+    assert_that!(msg_view.bb(), eq(0));
+
+    let msg_mut: NestedMessageMut = msg.optional_nested_message_mut();
+    // test reading an int inside a mut
+    assert_that!(msg_mut.bb(), eq(0));
 }
 
 #[test]
diff --git a/rust/test/shared/simple_nested_test.rs b/rust/test/shared/simple_nested_test.rs
index daa654c..b5d6ba3 100644
--- a/rust/test/shared/simple_nested_test.rs
+++ b/rust/test/shared/simple_nested_test.rs
@@ -5,13 +5,49 @@
 // license that can be found in the LICENSE file or at
 // https://developers.google.com/open-source/licenses/bsd
 
+use googletest::prelude::*;
 use nested_proto::nest::Outer;
+use nested_proto::nest::Outer_::InnerMut;
+use nested_proto::nest::Outer_::InnerView;
 
 #[test]
-fn test_simple_nested_proto() {
+fn test_nested_views() {
     let outer_msg = Outer::new();
-    assert_eq!(outer_msg.inner().num(), 0);
-    assert!(!outer_msg.inner().boolean());
+    let inner_msg: InnerView<'_> = outer_msg.inner();
+    assert_that!(inner_msg.double(), eq(0.0));
+    assert_that!(inner_msg.float(), eq(0.0));
+    assert_that!(inner_msg.int32(), eq(0));
+    assert_that!(inner_msg.int64(), eq(0));
+    assert_that!(inner_msg.uint32(), eq(0));
+    assert_that!(inner_msg.uint64(), eq(0));
+    assert_that!(inner_msg.sint32(), eq(0));
+    assert_that!(inner_msg.sint64(), eq(0));
+    assert_that!(inner_msg.fixed32(), eq(0));
+    assert_that!(inner_msg.fixed64(), eq(0));
+    assert_that!(inner_msg.sfixed32(), eq(0));
+    assert_that!(inner_msg.sfixed64(), eq(0));
+    assert_that!(inner_msg.bool(), eq(false));
+}
+
+#[test]
+fn test_nested_muts() {
+    // TODO: add actual mutation logic, this just peeks at InnerMut at
+    // the moment
+    let mut outer_msg = Outer::new();
+    let inner_msg: InnerMut<'_> = outer_msg.inner_mut();
+    assert_that!(inner_msg.double(), eq(0.0));
+    assert_that!(inner_msg.float(), eq(0.0));
+    assert_that!(inner_msg.int32(), eq(0));
+    assert_that!(inner_msg.int64(), eq(0));
+    assert_that!(inner_msg.uint32(), eq(0));
+    assert_that!(inner_msg.uint64(), eq(0));
+    assert_that!(inner_msg.sint32(), eq(0));
+    assert_that!(inner_msg.sint64(), eq(0));
+    assert_that!(inner_msg.fixed32(), eq(0));
+    assert_that!(inner_msg.fixed64(), eq(0));
+    assert_that!(inner_msg.sfixed32(), eq(0));
+    assert_that!(inner_msg.sfixed64(), eq(0));
+    assert_that!(inner_msg.bool(), eq(false));
 }
 
 #[test]
diff --git a/rust/upb.rs b/rust/upb.rs
index dff07df..778dddc 100644
--- a/rust/upb.rs
+++ b/rust/upb.rs
@@ -261,6 +261,14 @@
         MutatorMessageRef { msg: msg.msg, arena: &msg.arena }
     }
 
+    pub fn from_parent(
+        _private: Private,
+        parent_msg: &'msg mut MessageInner,
+        message_field_ptr: RawMessage,
+    ) -> Self {
+        MutatorMessageRef { msg: message_field_ptr, arena: &parent_msg.arena }
+    }
+
     pub fn msg(&self) -> RawMessage {
         self.msg
     }
diff --git a/src/google/protobuf/compiler/rust/accessors/singular_message.cc b/src/google/protobuf/compiler/rust/accessors/singular_message.cc
index 26f3358..972f3cd 100644
--- a/src/google/protobuf/compiler/rust/accessors/singular_message.cc
+++ b/src/google/protobuf/compiler/rust/accessors/singular_message.cc
@@ -22,42 +22,82 @@
 
   auto prefix = "crate::" + GetCrateRelativeQualifiedPath(d);
 
-  if (field.is_cpp()) {
-    field.Emit({{"prefix", prefix},
-                {"field", field.desc().name()},
-                {"getter_thunk", Thunk(field, "get")}},
-               R"rs(
-          pub fn r#$field$(&self) -> $prefix$View {
-            // For C++ kernel, getters automatically return the
-            // default_instance if the field is unset.
-            let submsg = unsafe { $getter_thunk$(self.inner.msg) };
-            $prefix$View::new($pbi$::Private, submsg)
-          }
-        )rs");
-  } else {
-    field.Emit({{"prefix", prefix},
-                {"field", field.desc().name()},
-                {"getter_thunk", Thunk(field, "get")}},
-               R"rs(
-          pub fn r#$field$(&self) -> $prefix$View {
-            let submsg = unsafe { $getter_thunk$(self.inner.msg) };
-            // For upb, getters return null if the field is unset, so we need to
-            // check for null and return the default instance manually. Note that
-            // a null ptr received from upb manifests as Option::None
-            match submsg {
+  field.Emit(
+      {
+          {"prefix", prefix},
+          {"field", field.desc().name()},
+          {"getter_thunk", Thunk(field, "get")},
+          {"clearer_thunk", Thunk(field, "clear")},
+          {
+              "view_body",
+              [&] {
+                if (field.is_upb()) {
+                  field.Emit({}, R"rs(
+              let submsg = unsafe { $getter_thunk$(self.inner.msg) };
+              // For upb, getters return null if the field is unset, so we need
+              // to check for null and return the default instance manually.
+              // Note that a nullptr received from upb manifests as Option::None
+              match submsg {
                 // TODO:(b/304357029)
-                None => $prefix$View::new($pbi$::Private, $pbr$::ScratchSpace::zeroed_block($pbi$::Private)),
+                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(
+              // For C++ kernel, getters automatically return the
+              // default_instance if the field is unset.
+              let submsg = unsafe { $getter_thunk$(self.inner.msg) };
+              $prefix$View::new($pbi$::Private, submsg)
+        )rs");
+                }
+              },
+          },
+          {"submessage_mut",
+           [&] {
+             if (field.is_upb()) {
+               field.Emit({}, R"rs(
+                 let submsg_opt = unsafe { $getter_thunk$(self.inner.msg) };
+                 match submsg_opt {
+                   None => {
+                     $prefix$Mut::new($pbi$::Private,
+                       &mut self.inner,
+                       $pbr$::ScratchSpace::zeroed_block($pbi$::Private))
+                   },
+                   Some(submsg) => {
+                     $prefix$Mut::new($pbi$::Private, &mut self.inner, submsg)
+                }
+              }
+        )rs");
+             } else {
+               field.Emit({}, R"rs(
+                    let submsg = unsafe { $getter_thunk$(self.inner.msg) };
+                    $prefix$Mut::new($pbi$::Private, &mut self.inner, submsg)
+                  )rs");
+             }
+           }},
+      },
+      R"rs(
+            pub fn r#$field$(&self) -> $prefix$View {
+              $view_body$
+            }
+
+            pub fn $field$_mut(&mut self) -> $prefix$Mut {
+              $submessage_mut$
+            }
+
+            pub fn $field$_clear(&mut self) {
+              unsafe { $clearer_thunk$(self.inner.msg) }
+            }
+        )rs");
 }
 
 void SingularMessage::InExternC(Context<FieldDescriptor> field) const {
   field.Emit(
       {
           {"getter_thunk", Thunk(field, "get")},
+          {"clearer_thunk", Thunk(field, "clear")},
           {"ReturnType",
            [&] {
              if (field.is_cpp()) {
@@ -72,6 +112,7 @@
       },
       R"rs(
                   fn $getter_thunk$(raw_msg: $pbi$::RawMessage) -> $ReturnType$;
+                  fn $clearer_thunk$(raw_msg: $pbi$::RawMessage);
                )rs");
 }
 
@@ -79,11 +120,13 @@
   field.Emit({{"QualifiedMsg",
                cpp::QualifiedClassName(field.desc().containing_type())},
               {"getter_thunk", Thunk(field, "get")},
+              {"clearer_thunk", Thunk(field, "clear")},
               {"field", cpp::FieldName(&field.desc())}},
              R"cc(
                const void* $getter_thunk$($QualifiedMsg$* msg) {
                  return static_cast<const void*>(&msg->$field$());
                }
+               void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
              )cc");
 }
 
diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc
index 585b7aa..ecb6d56 100644
--- a/src/google/protobuf/compiler/rust/generator.cc
+++ b/src/google/protobuf/compiler/rust/generator.cc
@@ -98,6 +98,7 @@
                         pub use crate::$mod$::$Msg$;
                         // TODO Address use for imported crates
                         pub use crate::$mod$::$Msg$View;
+                        pub use crate::$mod$::$Msg$Mut;
                       )rs");
   }
 }
diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc
index 5b4a2fd..cd01d7a 100644
--- a/src/google/protobuf/compiler/rust/message.cc
+++ b/src/google/protobuf/compiler/rust/message.cc
@@ -181,19 +181,33 @@
          type == FieldDescriptor::TYPE_BOOL;
 }
 
-void GenerateSubView(Context<FieldDescriptor> field) {
+void GetterForViewOrMut(Context<FieldDescriptor> field, bool is_mut) {
+  // If we're dealing with a Mut, the getter must be supplied self.inner.msg()
+  // whereas a View has to be supplied self.msg
   field.Emit(
       {
           {"field", field.desc().name()},
           {"getter_thunk", Thunk(field, "get")},
+          {"self", is_mut ? "self.inner.msg()" : "self.msg"},
           {"Scalar", PrimitiveRsTypeName(field.desc())},
       },
       R"rs(
-      pub fn r#$field$(&self) -> $Scalar$ { unsafe {
-        $getter_thunk$(self.msg)
-      } }
-    )rs");
+    pub fn r#$field$(&self) -> $Scalar$ {
+      unsafe { $getter_thunk$($self$) }
+    }
+  )rs");
 }
+
+void AccessorsForViewOrMut(Context<Descriptor> msg, bool is_mut) {
+  for (int i = 0; i < msg.desc().field_count(); ++i) {
+    auto field = msg.WithDesc(*msg.desc().field(i));
+    if (field.desc().is_repeated()) continue;
+    if (!IsSimpleScalar(field.desc().type())) continue;
+    GetterForViewOrMut(field, is_mut);
+    msg.printer().PrintRaw("\n");
+  }
+}
+
 }  // namespace
 
 void GenerateRs(Context<Descriptor> msg) {
@@ -278,17 +292,8 @@
                  }  // mod $Msg$_
                 )rs");
            }},
-          {"subviews",
-           [&] {
-             for (int i = 0; i < msg.desc().field_count(); ++i) {
-               auto field = msg.WithDesc(*msg.desc().field(i));
-               if (field.desc().is_repeated()) continue;
-               if (!IsSimpleScalar(field.desc().type())) continue;
-               GenerateSubView(field);
-               msg.printer().PrintRaw("\n");
-             }
-           }},
-      },
+          {"accessor_fns_for_views", [&] {AccessorsForViewOrMut(msg, false);}},
+          {"accessor_fns_for_muts", [&] {AccessorsForViewOrMut(msg, true);}}},
       R"rs(
         #[allow(non_camel_case_types)]
         // TODO: Implement support for debug redaction
@@ -321,7 +326,7 @@
           pub fn new(_private: $pbi$::Private, msg: $pbi$::RawMessage) -> Self {
             Self { msg, _phantom: std::marker::PhantomData }
           }
-          $subviews$
+          $accessor_fns_for_views$
         }
 
         // SAFETY:
@@ -352,10 +357,25 @@
 
         #[derive(Debug)]
         #[allow(dead_code)]
+        #[allow(non_camel_case_types)]
         pub struct $Msg$Mut<'a> {
           inner: $pbr$::MutatorMessageRef<'a>,
         }
 
+        impl<'a> $Msg$Mut<'a> {
+          #[doc(hidden)]
+          pub fn new(_private: $pbi$::Private,
+                     parent: &'a mut $pbr$::MessageInner,
+                     msg: $pbi$::RawMessage)
+            -> Self {
+            Self {
+              inner: $pbr$::MutatorMessageRef::from_parent(
+                       $pbi$::Private, parent, msg)
+            }
+          }
+          $accessor_fns_for_muts$
+        }
+
         // SAFETY:
         // - `$Msg$Mut` does not perform any shared mutation.
         // - `$Msg$Mut` is not `Send`, and so even in the presence of mutator