Remove the defensive copy on singular string setter

Calling into_proxied() already does a copy and before this change we were doing a second one.

I am not using set_allocated_<field(std::string* s) because the method is not generated when [features.(pb.cpp).string_type = VIEW] is specified.

PiperOrigin-RevId: 650612909
diff --git a/rust/cpp.rs b/rust/cpp.rs
index c33e71d..c5257ba 100644
--- a/rust/cpp.rs
+++ b/rust/cpp.rs
@@ -71,7 +71,7 @@
     /// It is only meant to provide type safety for raw pointers
     /// which are manipulated behind FFI.
     #[repr(C)]
-    pub(super) struct CppStdStringData {
+    pub struct CppStdStringData {
         _data: [u8; 0],
         _marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
     }
@@ -87,7 +87,7 @@
 pub type RawMap = NonNull<_opaque_pointees::RawMapData>;
 
 /// A raw pointer to a std::string.
-type CppStdString = NonNull<_opaque_pointees::CppStdStringData>;
+pub type CppStdString = NonNull<_opaque_pointees::CppStdStringData>;
 
 /// Kernel-specific owned `string` and `bytes` field type.
 #[derive(Debug)]
@@ -109,6 +109,11 @@
         // SAFETY: `self.owned_ptr` points to a valid std::string object.
         unsafe { proto2_rust_cpp_string_to_view(self.owned_ptr).as_ref() }
     }
+
+    pub fn into_raw(self, _private: Private) -> CppStdString {
+        let s = ManuallyDrop::new(self);
+        s.owned_ptr
+    }
 }
 
 impl From<&[u8]> for InnerProtoString {
@@ -219,7 +224,7 @@
     pub fn into_vec(self) -> Vec<u8> {
         // We need to prevent self from being dropped, because we are going to transfer
         // ownership of self.data to the Vec<u8>.
-        let s = std::mem::ManuallyDrop::new(self);
+        let s = ManuallyDrop::new(self);
 
         unsafe {
             // SAFETY:
@@ -352,14 +357,6 @@
     }
 }
 
-pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
-    _msg_ref: MutatorMessageRef<'msg>,
-    val: &'msg [u8],
-) -> &'msg [u8] {
-    // Nothing to do, the message manages its own string memory for C++.
-    val
-}
-
 /// The raw type-erased version of an owned `Repeated`.
 #[derive(Debug)]
 pub struct InnerRepeated {
@@ -430,8 +427,7 @@
     }
 
     fn into_insertelem(v: Self) -> CppStdString {
-        let v = ManuallyDrop::new(v);
-        v.inner.owned_ptr
+        v.into_inner(Private).into_raw(Private)
     }
 }
 
@@ -444,8 +440,7 @@
     }
 
     fn into_insertelem(v: Self) -> CppStdString {
-        let v = ManuallyDrop::new(v);
-        v.inner.owned_ptr
+        v.into_inner(Private).into_raw(Private)
     }
 }
 
@@ -817,13 +812,11 @@
 }
 
 fn protostr_into_cppstdstring(val: ProtoString) -> CppStdString {
-    let m = ManuallyDrop::new(val);
-    m.inner.owned_ptr
+    val.into_inner(Private).into_raw(Private)
 }
 
 fn protobytes_into_cppstdstring(val: ProtoBytes) -> CppStdString {
-    let m = ManuallyDrop::new(val);
-    m.inner.owned_ptr
+    val.into_inner(Private).into_raw(Private)
 }
 
 // Warning: this function is unsound on its own! `val.as_ref()` must be safe to
diff --git a/rust/string.rs b/rust/string.rs
index 3f82e14..a94f4ef 100644
--- a/rust/string.rs
+++ b/rust/string.rs
@@ -29,6 +29,15 @@
     pub(crate) inner: InnerProtoString,
 }
 
+impl ProtoBytes {
+    // Returns the kernel-specific container. This method is private in spirit and
+    // must not be called by a user.
+    #[doc(hidden)]
+    pub fn into_inner(self, _private: Private) -> InnerProtoString {
+        self.inner
+    }
+}
+
 impl AsRef<[u8]> for ProtoBytes {
     fn as_ref(&self) -> &[u8] {
         self.inner.as_bytes()
@@ -162,6 +171,13 @@
     pub fn as_bytes(&self) -> &[u8] {
         self.inner.as_bytes()
     }
+
+    // Returns the kernel-specific container. This method is private in spirit and
+    // must not be called by a user.
+    #[doc(hidden)]
+    pub fn into_inner(self, _private: Private) -> InnerProtoString {
+        self.inner
+    }
 }
 
 impl From<ProtoString> for ProtoBytes {
diff --git a/rust/upb.rs b/rust/upb.rs
index e53e0aa..5a8cdfa 100644
--- a/rust/upb.rs
+++ b/rust/upb.rs
@@ -128,13 +128,6 @@
     }
 }
 
-pub fn copy_bytes_in_arena_if_needed_by_runtime<'msg>(
-    msg_ref: MutatorMessageRef<'msg>,
-    val: &'msg [u8],
-) -> &'msg [u8] {
-    copy_bytes_in_arena(msg_ref.arena, val)
-}
-
 fn copy_bytes_in_arena<'msg>(arena: &'msg Arena, val: &'msg [u8]) -> &'msg [u8] {
     // SAFETY: the alignment of `[u8]` is less than `UPB_MALLOC_ALIGN`.
     let new_alloc = unsafe { arena.alloc(Layout::for_value(val)) };
@@ -157,6 +150,12 @@
     pub(crate) fn as_bytes(&self) -> &[u8] {
         &self.0
     }
+
+    #[doc(hidden)]
+    pub fn into_raw_parts(self, _private: Private) -> (PtrAndLen, Arena) {
+        let (data_ptr, arena) = self.0.into_parts();
+        (unsafe { data_ptr.as_ref().into() }, arena)
+    }
 }
 
 impl From<&[u8]> for InnerProtoString {
@@ -617,12 +616,11 @@
     ) -> upb_MessageValue {
         // SAFETY: The arena memory is not freed due to `ManuallyDrop`.
         let parent_arena = ManuallyDrop::new(unsafe { Arena::from_raw(raw_parent_arena) });
-        let (data, arena) = val.inner.0.into_parts();
 
+        let (view, arena) = val.inner.into_raw_parts(Private);
         parent_arena.fuse(&arena);
 
-        let msg_val = Self::to_message_value(unsafe { data.as_ref() });
-        msg_val
+        upb_MessageValue { str_val: view }
     }
 
     unsafe fn from_message_value<'msg>(msg: upb_MessageValue) -> View<'msg, ProtoBytes> {
diff --git a/src/google/protobuf/compiler/rust/accessors/singular_string.cc b/src/google/protobuf/compiler/rust/accessors/singular_string.cc
index d37bb75..99f8b9f 100644
--- a/src/google/protobuf/compiler/rust/accessors/singular_string.cc
+++ b/src/google/protobuf/compiler/rust/accessors/singular_string.cc
@@ -66,28 +66,46 @@
               }
           )rs");
            }},
-          {"setter",
+          {"setter_impl",
            [&] {
-             if (accessor_case == AccessorCase::VIEW) return;
-             ctx.Emit({{"as_ref_method",
-                        (field.type() == FieldDescriptor::TYPE_STRING
-                             ? "as_bytes()"
-                             : "as_ref()")}},
-                      R"rs(
-              pub fn set_$raw_field_name$(&mut self, val: impl $pb$::IntoProxied<$proxied_type$>) {
-                let into_proxied = val.into_proxied($pbi$::Private);
-                let string_view: $pbr$::PtrAndLen =
-                  $pbr$::copy_bytes_in_arena_if_needed_by_runtime(
-                    self.as_mutator_message_ref($pbi$::Private),
-                    into_proxied.$as_ref_method$,
-                  ).into();
+             if (ctx.is_cpp()) {
+               ctx.Emit(R"rs(
+                let s = val.into_proxied($pbi$::Private);
+                unsafe {
+                  $setter_thunk$(
+                    self.as_mutator_message_ref($pbi$::Private).msg(),
+                    s.into_inner($pbi$::Private).into_raw($pbi$::Private)
+                  );
+                }
+              )rs");
+             } else {
+               ctx.Emit(R"rs(
+                let s = val.into_proxied($pbi$::Private);
+                let (view, arena) =
+                  s.into_inner($pbi$::Private).into_raw_parts($pbi$::Private);
+
+                let mm_ref =
+                  self.as_mutator_message_ref($pbi$::Private);
+                let parent_arena = mm_ref.arena($pbi$::Private);
+
+                parent_arena.fuse(&arena);
 
                 unsafe {
                   $setter_thunk$(
                     self.as_mutator_message_ref($pbi$::Private).msg(),
-                    string_view
+                    view
                   );
                 }
+              )rs");
+             }
+           }},
+          {"setter",
+           [&] {
+             if (accessor_case == AccessorCase::VIEW) return;
+             ctx.Emit({},
+                      R"rs(
+              pub fn set_$raw_field_name$(&mut self, val: impl $pb$::IntoProxied<$proxied_type$>) {
+                $setter_impl$
               }
             )rs");
            }},
@@ -123,6 +141,18 @@
   ctx.Emit({{"hazzer_thunk", ThunkName(ctx, field, "has")},
             {"getter_thunk", ThunkName(ctx, field, "get")},
             {"setter_thunk", ThunkName(ctx, field, "set")},
+            {"setter",
+             [&] {
+               if (ctx.is_cpp()) {
+                 ctx.Emit(R"rs(
+                  fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::CppStdString);
+                )rs");
+               } else {
+                 ctx.Emit(R"rs(
+                  fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::PtrAndLen);
+                )rs");
+               }
+             }},
             {"clearer_thunk", ThunkName(ctx, field, "clear")},
             {"with_presence_fields_thunks",
              [&] {
@@ -136,7 +166,7 @@
            R"rs(
           $with_presence_fields_thunks$
           fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::PtrAndLen;
-          fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::PtrAndLen);
+          $setter$
         )rs");
 }
 
@@ -165,8 +195,9 @@
                absl::string_view val = msg->$field$();
                return ::google::protobuf::rust::PtrAndLen(val.data(), val.size());
              }
-             void $setter_thunk$($QualifiedMsg$* msg, ::google::protobuf::rust::PtrAndLen s) {
-               msg->set_$field$(absl::string_view(s.ptr, s.len));
+             void $setter_thunk$($QualifiedMsg$* msg, std::string* s) {
+               msg->set_$field$(std::move(*s));
+               delete s;
              }
            )cc");
 }