In `SerializedMessage{,Backward}Writer`, rename `CopyString()` to
`WriteString()`, merging it with other overloads.

Add direct support for `CordIteratorSpan` in `WriteString()`. It is convertible
to `absl::Cord`, but the stringification mechanism does not find that.

Rationale: it is not that important to explicitly indicate whether reading is
destructive or not, especially since `ReaderSpan` is move-only. It is more
important to be able to treat `ReaderSpan`, `CordIteratorSpan`, and
`absl::string_view` uniformly.
PiperOrigin-RevId: 847835642
diff --git a/riegeli/messages/BUILD b/riegeli/messages/BUILD
index c9b167f..4d1852a 100644
--- a/riegeli/messages/BUILD
+++ b/riegeli/messages/BUILD
@@ -199,6 +199,7 @@
         "//riegeli/base:any",
         "//riegeli/base:arithmetic",
         "//riegeli/base:assert",
+        "//riegeli/base:buffering",
         "//riegeli/base:constexpr",
         "//riegeli/base:cord_iterator_span",
         "//riegeli/base:types",
@@ -234,6 +235,8 @@
         "//riegeli/base:any",
         "//riegeli/base:arithmetic",
         "//riegeli/base:assert",
+        "//riegeli/base:buffering",
+        "//riegeli/base:cord_iterator_span",
         "//riegeli/base:types",
         "//riegeli/bytes:backward_writer",
         "//riegeli/bytes:copy_all",
diff --git a/riegeli/messages/field_handlers.h b/riegeli/messages/field_handlers.h
index 2a15b45..d7afde0 100644
--- a/riegeli/messages/field_handlers.h
+++ b/riegeli/messages/field_handlers.h
@@ -408,7 +408,8 @@
 // `ReaderSpan<>`, `CordIteratorSpan`, and `absl::string_view`, then the action
 // parameter can be declared as `auto`. This is convenient if the implementation
 // can treat these types uniformly, e.g. when the value is passed to
-// `riegeli::ParseMessage()` or `SerializedMessageReader2::ReadMessage()`.
+// `riegeli::ParseMessage()`, `SerializedMessageReader2::ReadMessage()`, or
+// `SerializedMessageWriter::WriteString()`.
 //
 // Alternatively, the action can use `absl::Overload{}` to provide variants with
 // separate implementations for these parameter types.
diff --git a/riegeli/messages/serialized_message_backward_writer.cc b/riegeli/messages/serialized_message_backward_writer.cc
index a2152bf..2bc2bd9 100644
--- a/riegeli/messages/serialized_message_backward_writer.cc
+++ b/riegeli/messages/serialized_message_backward_writer.cc
@@ -25,6 +25,8 @@
 #include "absl/strings/str_cat.h"
 #include "riegeli/base/any.h"
 #include "riegeli/base/assert.h"
+#include "riegeli/base/buffering.h"
+#include "riegeli/base/cord_iterator_span.h"
 #include "riegeli/base/types.h"
 #include "riegeli/bytes/backward_writer.h"
 #include "riegeli/bytes/copy_all.h"
@@ -42,15 +44,16 @@
                    length));
 }
 
-absl::Status SerializedMessageBackwardWriter::CopyStringFailed(
+absl::Status SerializedMessageBackwardWriter::WriteStringFailed(
     Reader& src, BackwardWriter& dest) {
-  return !dest.ok() ? dest.status()
-                    : src.StatusOrAnnotate(absl::InvalidArgumentError(
-                          "Could not read a length-delimited field"));
+  return !dest.ok()
+             ? dest.status()
+             : src.StatusOrAnnotate(absl::InvalidArgumentError(
+                   "Could not read contents for a length-delimited field"));
 }
 
-absl::Status SerializedMessageBackwardWriter::CopyString(int field_number,
-                                                         AnyRef<Reader*> src) {
+absl::Status SerializedMessageBackwardWriter::WriteString(int field_number,
+                                                          AnyRef<Reader*> src) {
   if (src.IsOwning()) src->SetReadAllHint(true);
   const Position pos_after = writer().pos();
   if (absl::Status status = CopyAll(std::move(src), writer());
@@ -62,6 +65,19 @@
   return WriteLengthUnchecked(field_number, writer().pos() - pos_after);
 }
 
+absl::Status SerializedMessageBackwardWriter::WriteString(
+    int field_number, CordIteratorSpan src) {
+  if (src.length() <= kMaxBytesToCopy) {
+    if (ABSL_PREDICT_FALSE(!writer().Push(src.length()))) {
+      return writer().status();
+    }
+    writer().move_cursor(src.length());
+    CordIteratorSpan::Read(src.iterator(), src.length(), writer().cursor());
+    return WriteLengthUnchecked(field_number, src.length());
+  }
+  return WriteString(field_number, std::move(src).ToCord());
+}
+
 void SerializedMessageBackwardWriter::OpenLengthDelimited() {
   submessages_.push_back(writer().pos());
 }
diff --git a/riegeli/messages/serialized_message_backward_writer.h b/riegeli/messages/serialized_message_backward_writer.h
index 88cb8b3..8699555 100644
--- a/riegeli/messages/serialized_message_backward_writer.h
+++ b/riegeli/messages/serialized_message_backward_writer.h
@@ -28,11 +28,11 @@
 #include "absl/base/nullability.h"
 #include "absl/base/optimization.h"
 #include "absl/status/status.h"
-#include "absl/strings/string_view.h"
 #include "google/protobuf/message_lite.h"
 #include "riegeli/base/any.h"
 #include "riegeli/base/arithmetic.h"
 #include "riegeli/base/assert.h"
+#include "riegeli/base/cord_iterator_span.h"
 #include "riegeli/base/types.h"
 #include "riegeli/bytes/backward_writer.h"
 #include "riegeli/bytes/limiting_reader.h"
@@ -158,19 +158,10 @@
     requires(IsStringifiable<Values>::value && ...)
 #endif
   absl::Status WriteString(int field_number, Values&&... values);
-
-  // Writes the field tag of a length-delimited field and copies the field value
-  // from a `Reader`.
-  //
-  // For `absl::string_view`, this is equivalent to `WriteString()`.
-  // This is useful for generic handlers of length-delimited fields for
-  // `SerializedMessageReader2`.
-  absl::Status CopyString(int field_number, AnyRef<Reader*> src);
+  absl::Status WriteString(int field_number, AnyRef<Reader*> src);
   template <typename ReaderType>
-  absl::Status CopyString(int field_number, ReaderSpan<ReaderType> src);
-  absl::Status CopyString(int field_number, absl::string_view src) {
-    return WriteString(field_number, src);
-  }
+  absl::Status WriteString(int field_number, ReaderSpan<ReaderType> src);
+  absl::Status WriteString(int field_number, CordIteratorSpan src);
 
   // Writes the field tag of a length-delimited field and serializes a message
   // as the field value.
@@ -245,7 +236,7 @@
 
  private:
   ABSL_ATTRIBUTE_COLD static absl::Status LengthOverflowError(Position length);
-  ABSL_ATTRIBUTE_COLD static absl::Status CopyStringFailed(
+  ABSL_ATTRIBUTE_COLD static absl::Status WriteStringFailed(
       Reader& src, BackwardWriter& dest);
 
   BackwardWriter* absl_nullable dest_ = nullptr;
@@ -503,7 +494,7 @@
 }
 
 template <typename ReaderType>
-absl::Status SerializedMessageBackwardWriter::CopyString(
+absl::Status SerializedMessageBackwardWriter::WriteString(
     int field_number, ReaderSpan<ReaderType> src) {
   if (ABSL_PREDICT_FALSE(src.length() >
                          uint32_t{std::numeric_limits<int32_t>::max()})) {
@@ -511,7 +502,7 @@
   }
   if (ABSL_PREDICT_FALSE(
           !src.reader().Copy(IntCast<size_t>(src.length()), writer()))) {
-    return CopyStringFailed(src.reader(), writer());
+    return WriteStringFailed(src.reader(), writer());
   }
   return WriteLengthUnchecked(field_number, src.length());
 }
diff --git a/riegeli/messages/serialized_message_writer.cc b/riegeli/messages/serialized_message_writer.cc
index 8bbf2d7..2b3999f 100644
--- a/riegeli/messages/serialized_message_writer.cc
+++ b/riegeli/messages/serialized_message_writer.cc
@@ -29,6 +29,8 @@
 #include "riegeli/base/any.h"
 #include "riegeli/base/arithmetic.h"
 #include "riegeli/base/assert.h"
+#include "riegeli/base/buffering.h"
+#include "riegeli/base/cord_iterator_span.h"
 #include "riegeli/base/types.h"
 #include "riegeli/bytes/cord_writer.h"
 #include "riegeli/bytes/limiting_reader.h"
@@ -46,22 +48,23 @@
                    length));
 }
 
-absl::Status SerializedMessageWriter::CopyStringFailed(Reader& src,
-                                                       Writer& dest) {
-  return !dest.ok() ? dest.status()
-                    : src.StatusOrAnnotate(absl::InvalidArgumentError(
-                          "Could not read a length-delimited field"));
+absl::Status SerializedMessageWriter::WriteStringFailed(Reader& src,
+                                                        Writer& dest) {
+  return !dest.ok()
+             ? dest.status()
+             : src.StatusOrAnnotate(absl::InvalidArgumentError(
+                   "Could not read contents for a length-delimited field"));
 }
 
-absl::Status SerializedMessageWriter::CopyString(int field_number,
-                                                 AnyRef<Reader*> src) {
+absl::Status SerializedMessageWriter::WriteString(int field_number,
+                                                  AnyRef<Reader*> src) {
   if (src.IsOwning()) src->SetReadAllHint(true);
   if (src->SupportsSize()) {
     const std::optional<Position> size = src->Size();
     if (ABSL_PREDICT_FALSE(size == std::nullopt)) return src->status();
-    if (absl::Status status =
-            CopyString(field_number,
-                       ReaderSpan(src.get(), SaturatingSub(*size, src->pos())));
+    if (absl::Status status = WriteString(
+            field_number,
+            ReaderSpan(src.get(), SaturatingSub(*size, src->pos())));
         ABSL_PREDICT_FALSE(!status.ok())) {
       return status;
     }
@@ -79,6 +82,23 @@
   }
 }
 
+absl::Status SerializedMessageWriter::WriteString(int field_number,
+                                                  CordIteratorSpan src) {
+  if (src.length() <= kMaxBytesToCopy) {
+    if (absl::Status status = WriteLengthUnchecked(field_number, src.length());
+        ABSL_PREDICT_FALSE(!status.ok())) {
+      return status;
+    }
+    if (ABSL_PREDICT_FALSE(!writer().Push(src.length()))) {
+      return writer().status();
+    }
+    CordIteratorSpan::Read(src.iterator(), src.length(), writer().cursor());
+    writer().move_cursor(src.length());
+    return absl::OkStatus();
+  }
+  return WriteString(field_number, std::move(src).ToCord());
+}
+
 void SerializedMessageWriter::OpenLengthDelimited() {
   writer_ = &submessages_.emplace_back();
 }
diff --git a/riegeli/messages/serialized_message_writer.h b/riegeli/messages/serialized_message_writer.h
index 7f6dbbb..368bfda 100644
--- a/riegeli/messages/serialized_message_writer.h
+++ b/riegeli/messages/serialized_message_writer.h
@@ -154,19 +154,10 @@
     requires(IsStringifiable<Values>::value && ...)
 #endif
   absl::Status WriteString(int field_number, Values&&... values);
-
-  // Writes the field tag of a length-delimited field and copies the field value
-  // from a `Reader`.
-  //
-  // For `absl::string_view`, this is equivalent to `WriteString()`.
-  // This is useful for generic handlers of length-delimited fields for
-  // `SerializedMessageReader2`.
-  absl::Status CopyString(int field_number, AnyRef<Reader*> src);
+  absl::Status WriteString(int field_number, AnyRef<Reader*> src);
   template <typename ReaderType>
-  absl::Status CopyString(int field_number, ReaderSpan<ReaderType> src);
-  absl::Status CopyString(int field_number, absl::string_view src) {
-    return WriteString(field_number, src);
-  }
+  absl::Status WriteString(int field_number, ReaderSpan<ReaderType> src);
+  absl::Status WriteString(int field_number, CordIteratorSpan src);
 
   // Writes the field tag of a length-delimited field and serializes a message
   // as the field value.
@@ -329,8 +320,8 @@
 
  private:
   ABSL_ATTRIBUTE_COLD static absl::Status LengthOverflowError(Position length);
-  ABSL_ATTRIBUTE_COLD static absl::Status CopyStringFailed(Reader& src,
-                                                           Writer& dest);
+  ABSL_ATTRIBUTE_COLD static absl::Status WriteStringFailed(Reader& src,
+                                                            Writer& dest);
 
   Writer* absl_nullable dest_ = nullptr;
   std::vector<CordWriter<absl::Cord>> submessages_;
@@ -393,7 +384,8 @@
 
   absl::Status DynamicHandleLengthDelimitedFromReader(
       int field_number, ReaderSpan<> repr, Context&... context) const {
-    return message_writer(context...).CopyString(field_number, std::move(repr));
+    return message_writer(context...)
+        .WriteString(field_number, std::move(repr));
   }
 
   absl::Status DynamicHandleLengthDelimitedFromCord(
@@ -702,14 +694,14 @@
 }
 
 template <typename ReaderType>
-absl::Status SerializedMessageWriter::CopyString(int field_number,
-                                                 ReaderSpan<ReaderType> src) {
+absl::Status SerializedMessageWriter::WriteString(int field_number,
+                                                  ReaderSpan<ReaderType> src) {
   if (absl::Status status = WriteLengthUnchecked(field_number, src.length());
       ABSL_PREDICT_FALSE(!status.ok())) {
     return status;
   }
   if (ABSL_PREDICT_FALSE(!src.reader().Copy(src.length(), writer()))) {
-    return CopyStringFailed(src.reader(), writer());
+    return WriteStringFailed(src.reader(), writer());
   }
   return absl::OkStatus();
 }