internal change

PiperOrigin-RevId: 998993134
diff --git a/rust/cpp_kernel/reflection.cc b/rust/cpp_kernel/reflection.cc
index 48c4649..9ce5e3a 100644
--- a/rust/cpp_kernel/reflection.cc
+++ b/rust/cpp_kernel/reflection.cc
@@ -10,12 +10,15 @@
 
 // Converts a message to its TextFormat representation.
 google::protobuf::rust::RustStringRawParts proto2_rust_Message_print_to_text_format(
-    const google::protobuf::MessageLite* m) {
+    const google::protobuf::MessageLite* m, bool single_line, bool hide_unknown_fields) {
   const auto* msg = google::protobuf::DynamicCastMessage<google::protobuf::Message>(m);
   // This should always hold because the Rust API requires `WithReflection`.
   ABSL_CHECK(msg != nullptr) << "Message does not support reflection.";
+  google::protobuf::TextFormat::Printer printer;
+  printer.SetSingleLineMode(single_line);
+  printer.SetHideUnknownFields(hide_unknown_fields);
   std::string text;
-  ABSL_CHECK(google::protobuf::TextFormat::PrintToString(*msg, &text));
+  ABSL_CHECK(printer.PrintToString(*msg, &text));
   return google::protobuf::rust::RustStringRawParts(text);
 }
 
diff --git a/rust/cpp_kernel/reflection.rs b/rust/cpp_kernel/reflection.rs
index 15197be..6ee19ac 100644
--- a/rust/cpp_kernel/reflection.rs
+++ b/rust/cpp_kernel/reflection.rs
@@ -21,27 +21,33 @@
     /// From reflection.cc
     ///
     /// # Safety
-    /// - `m` is a legally dereferenceable MessageLite* that supports
-    ///   reflection.
-    fn proto2_rust_Message_print_to_text_format(m: RawMessage) -> RustStringRawParts;
+    /// - `m` is a legally dereferenceable MessageLite* that supports reflection.
+    fn proto2_rust_Message_print_to_text_format(
+        m: RawMessage,
+        single_line: bool,
+        hide_unknown_fields: bool,
+    ) -> RustStringRawParts;
 
     /// From reflection.cc
     ///
     /// # Safety
-    /// - `m` is a legally dereferenceable and mutable MessageLite* that
-    ///   supports reflection.
-    /// - `input` is a valid `PtrAndLen` pointing to readable memory for its
-    ///   length.
+    /// - `m` is a legally dereferenceable and mutable MessageLite* that supports reflection.
+    /// - `input` is a valid `PtrAndLen` pointing to readable memory for its length.
     fn proto2_rust_Message_parse_from_text_format(m: RawMessage, input: PtrAndLen) -> bool;
 }
 
-/// Returns the protobuf TextFormat representation of `msg`.
+/// Returns the protobuf TextFormat representation of `msg` with custom options.
 #[cfg(not(lite_runtime))]
-pub fn print_to_text_format<T: crate::WithReflection>(msg: &T) -> String {
+pub fn print_to_text_format<T: crate::WithReflection>(
+    msg: &T,
+    single_line: bool,
+    hide_unknown_fields: bool,
+) -> String {
     let raw = msg.as_view().get_raw_message(Private);
     // SAFETY: `raw` points to a live message, and `WithReflection` guarantees it
     // supports reflection.
-    unsafe { proto2_rust_Message_print_to_text_format(raw) }.into()
+    unsafe { proto2_rust_Message_print_to_text_format(raw, single_line, hide_unknown_fields) }
+        .into()
 }
 
 /// Parses a message from its protobuf TextFormat representation.
@@ -50,8 +56,8 @@
     let mut msg = T::default();
     let raw = msg.get_raw_message_mut(Private);
     // SAFETY:
-    // - `raw` points to a live, mutable message, and `WithReflection`
-    //   guarantees it supports reflection.
+    // - `raw` points to a live, mutable message, and `WithReflection` guarantees it supports
+    //   reflection.
     // - `input` is converted from a valid `&str` slice.
     unsafe { proto2_rust_Message_parse_from_text_format(raw, input.as_bytes().into()) }
         .then_some(msg)
diff --git a/rust/test/shared/reflection_test.rs b/rust/test/shared/reflection_test.rs
new file mode 100644
index 0000000..b921230
--- /dev/null
+++ b/rust/test/shared/reflection_test.rs
@@ -0,0 +1,6 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2026 Google LLC.  All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
diff --git a/rust/test/upb/reflection_test.rs b/rust/test/upb/reflection_test.rs
deleted file mode 100644
index ec70403..0000000
--- a/rust/test/upb/reflection_test.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2026 Google LLC.  All rights reserved.
-//
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file or at
-// https://developers.google.com/open-source/licenses/bsd
-
-#[cfg(test)]
-mod tests {
-    use googletest::prelude::*;
-    use unittest_rust_proto::TestAllTypes;
-
-    #[gtest]
-    fn test_print_to_text_format() {
-        let mut msg = TestAllTypes::new();
-        msg.set_optional_int32(42);
-        msg.set_optional_string("super secret");
-
-        let text = protobuf::text_format::print(&msg);
-        expect_eq!(text, "optional_int32: 42\noptional_string: \"super secret\"\n");
-    }
-}
diff --git a/rust/upb/lib.rs b/rust/upb/lib.rs
index 023bac7..fbf494f 100644
--- a/rust/upb/lib.rs
+++ b/rust/upb/lib.rs
@@ -14,7 +14,7 @@
 pub use associated_mini_table::{AssociatedMiniTable, AssociatedMiniTableEnum};
 
 mod text;
-pub use text::debug_string;
+pub use text::{debug_string, TextEncodeOptions};
 
 mod message;
 pub use message::MessagePtr;
diff --git a/rust/upb/reflection.rs b/rust/upb/reflection.rs
index 5cb397f..c5c7783 100644
--- a/rust/upb/reflection.rs
+++ b/rust/upb/reflection.rs
@@ -23,7 +23,10 @@
 use reflection::message_def::RawMessageDef;
 use reflection::upb_TextEncode;
 
-use upb::{Arena, MessagePtr, RawMiniTable, RawMiniTableEnum, RawMiniTableExtension, StringView};
+use upb::{
+    Arena, MessagePtr, RawMiniTable, RawMiniTableEnum, RawMiniTableExtension, StringView,
+    TextEncodeOptions,
+};
 
 pub use reflection::def_pool::upb_DefPool_Init;
 pub use reflection::def_pool::RawDefPoolInit as DefPoolInitPtr;
@@ -125,11 +128,12 @@
     msg: MessagePtr<T>,
     def: MessageDef<'pool>,
     ext_pool: Option<&DefPool>,
-    options: u32,
+    options: TextEncodeOptions,
 ) -> String {
     let msg = msg.raw();
     let def_raw = def.raw();
     let ext_pool_raw = ext_pool.map(|p| p.raw());
+    let options = options.to_bits();
 
     // Only find out the length first to then allocate a buffer of the minimum size
     // needed.
@@ -138,9 +142,8 @@
     // - `def` is valid per safety requirements of this function.
     // - `ext_pool` is valid per safety requirements of this function.
     // - `buf` is null and `size` is 0.
-    let min_len = unsafe {
-        upb_TextEncode(msg, def_raw, ext_pool_raw, options as i32, core::ptr::null_mut(), 0)
-    };
+    let min_len =
+        unsafe { upb_TextEncode(msg, def_raw, ext_pool_raw, options, core::ptr::null_mut(), 0) };
     assert!(min_len < isize::MAX as usize);
 
     // +1 for the trailing NULL
@@ -149,9 +152,8 @@
     // SAFETY:
     // - `msg`, `def`, `ext_pool` are valid per safety requirements of this function.
     // - `buf` is legally writable for `buf.len()` bytes.
-    let written_len = unsafe {
-        upb_TextEncode(msg, def_raw, ext_pool_raw, options as i32, buf.as_mut_ptr(), buf.len())
-    };
+    let written_len =
+        unsafe { upb_TextEncode(msg, def_raw, ext_pool_raw, options, buf.as_mut_ptr(), buf.len()) };
     assert_eq!(min_len, written_len);
 
     // Drop the trailing NULL written by `upb_TextEncode`.
diff --git a/rust/upb/text.rs b/rust/upb/text.rs
index df319c2..92ac377 100644
--- a/rust/upb/text.rs
+++ b/rust/upb/text.rs
@@ -5,9 +5,34 @@
 // license that can be found in the LICENSE file or at
 // https://developers.google.com/open-source/licenses/bsd
 
-use super::sys::text::text::upb_DebugString;
+use super::sys::text::text::{text_encode_options, upb_DebugString};
 use super::{AssociatedMiniTable, MessagePtr};
 
+/// Options for upb's text encoders.
+/// This is only used for `text_encode` for now, but it might be used for `debug_string` in the
+/// future. That's why it must be in the non-reflection crate.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+pub struct TextEncodeOptions {
+    /// Print everything on a single line.
+    pub single_line: bool,
+    /// Do not print unknown fields.
+    pub skip_unknown: bool,
+}
+
+impl TextEncodeOptions {
+    /// The bitmask that upb's text encoders expect.
+    pub fn to_bits(self) -> i32 {
+        let mut bits = 0;
+        if self.single_line {
+            bits |= text_encode_options::SINGLE_LINE;
+        }
+        if self.skip_unknown {
+            bits |= text_encode_options::SKIP_UNKNOWN;
+        }
+        bits
+    }
+}
+
 /// Returns a string of field number to value entries of a message.
 ///
 /// # Safety
diff --git a/rust/upb_kernel/reflection.rs b/rust/upb_kernel/reflection.rs
index 2191d9f..7e83b96 100644
--- a/rust/upb_kernel/reflection.rs
+++ b/rust/upb_kernel/reflection.rs
@@ -11,6 +11,7 @@
 //! the message's `MessageDef` in the process-wide `DefPool` (see `def_pool.rs`), then hands both
 //! the message and the def to upb.
 
+use super::upb::TextEncodeOptions;
 use super::{message_def, upb_reflection, UpbGetMessagePtr, UpbWithReflection};
 use crate::__internal::Private;
 use crate::WithReflection;
@@ -22,15 +23,19 @@
 pub trait KernelWithReflection: UpbWithReflection + UpbGetMessagePtr<Msg = Self> {}
 impl<T: UpbWithReflection + UpbGetMessagePtr<Msg = T>> KernelWithReflection for T {}
 
-/// Returns the protobuf TextFormat representation of `msg`.
-pub fn print_to_text_format<T: WithReflection>(msg: &T) -> String {
+/// Returns the protobuf TextFormat representation of `msg` with custom options.
+pub fn print_to_text_format<T: WithReflection>(
+    msg: &T,
+    single_line: bool,
+    hide_unknown_fields: bool,
+) -> String {
     let ptr = msg.get_ptr(Private);
     let def = message_def::<T>();
+    let options = TextEncodeOptions { single_line, skip_unknown: hide_unknown_fields };
     // SAFETY:
     // - `ptr` points to a live message that `msg` keeps alive for the duration of the call.
     // - `def` describes `T`, and `WithReflection` guarantees `kernelWithReflection`, which
     //   guarantees `UpbGetMessagePtr<Msg = T>, therefore `ptr` is a `MessagePtr<T>`.
     // TODO: Pass the global DefPool as `ext_pool` so that extensions are printed.
-    // TODO: Support configuring options.
-    unsafe { upb_reflection::text_encode(ptr, def, None, 0) }
+    unsafe { upb_reflection::text_encode(ptr, def, None, options) }
 }