Refactor upb/rust directory to introduce separate files for each concept instead of a single blob.

PiperOrigin-RevId: 625333833
diff --git a/rust/upb/BUILD b/rust/upb/BUILD
index 2c19acc..894d495 100644
--- a/rust/upb/BUILD
+++ b/rust/upb/BUILD
@@ -14,8 +14,17 @@
     name = "upb",
     srcs = [
         "arena.rs",
+        "array.rs",
+        "ctype.rs",
+        "extension_registry.rs",
         "lib.rs",
+        "map.rs",
+        "message.rs",
+        "message_value.rs",
+        "mini_table.rs",
         "opaque_pointee.rs",
+        "string_view.rs",
+        "wire.rs",
     ],
     visibility = [
         "//rust:__subpackages__",
diff --git a/rust/upb/array.rs b/rust/upb/array.rs
new file mode 100644
index 0000000..8c0abf8
--- /dev/null
+++ b/rust/upb/array.rs
@@ -0,0 +1,42 @@
+use crate::opaque_pointee::opaque_pointee;
+use crate::{upb_MessageValue, upb_MutableMessageValue, CType, RawArena};
+use std::ptr::NonNull;
+
+opaque_pointee!(upb_Array);
+pub type RawArray = NonNull<upb_Array>;
+
+extern "C" {
+    pub fn upb_Array_New(a: RawArena, r#type: CType) -> RawArray;
+    pub fn upb_Array_Size(arr: RawArray) -> usize;
+    pub fn upb_Array_Set(arr: RawArray, i: usize, val: upb_MessageValue);
+    pub fn upb_Array_Get(arr: RawArray, i: usize) -> upb_MessageValue;
+    pub fn upb_Array_Append(arr: RawArray, val: upb_MessageValue, arena: RawArena) -> bool;
+    pub fn upb_Array_Resize(arr: RawArray, size: usize, arena: RawArena) -> bool;
+    pub fn upb_Array_MutableDataPtr(arr: RawArray) -> *mut std::ffi::c_void;
+    pub fn upb_Array_DataPtr(arr: RawArray) -> *const std::ffi::c_void;
+    pub fn upb_Array_GetMutable(arr: RawArray, i: usize) -> upb_MutableMessageValue;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn array_ffi_test() {
+        // SAFETY: FFI unit test uses C API under expected patterns.
+        unsafe {
+            let arena = crate::Arena::new();
+            let raw_arena = arena.raw();
+            let array = upb_Array_New(raw_arena, CType::Float);
+
+            assert!(upb_Array_Append(array, upb_MessageValue { float_val: 7.0 }, raw_arena));
+            assert!(upb_Array_Append(array, upb_MessageValue { float_val: 42.0 }, raw_arena));
+            assert_eq!(upb_Array_Size(array), 2);
+            assert!(matches!(upb_Array_Get(array, 1), upb_MessageValue { float_val: 42.0 }));
+
+            assert!(upb_Array_Resize(array, 3, raw_arena));
+            assert_eq!(upb_Array_Size(array), 3);
+            assert!(matches!(upb_Array_Get(array, 2), upb_MessageValue { float_val: 0.0 }));
+        }
+    }
+}
diff --git a/rust/upb/ctype.rs b/rust/upb/ctype.rs
new file mode 100644
index 0000000..346706a
--- /dev/null
+++ b/rust/upb/ctype.rs
@@ -0,0 +1,17 @@
+// Transcribed from google3/third_party/upb/upb/base/descriptor_constants.h
+#[repr(C)]
+#[allow(dead_code)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub enum CType {
+    Bool = 1,
+    Float = 2,
+    Int32 = 3,
+    UInt32 = 4,
+    Enum = 5,
+    Message = 6,
+    Double = 7,
+    Int64 = 8,
+    UInt64 = 9,
+    String = 10,
+    Bytes = 11,
+}
diff --git a/rust/upb/extension_registry.rs b/rust/upb/extension_registry.rs
new file mode 100644
index 0000000..b58b3f6
--- /dev/null
+++ b/rust/upb/extension_registry.rs
@@ -0,0 +1,5 @@
+use crate::opaque_pointee::opaque_pointee;
+use std::ptr::NonNull;
+
+opaque_pointee!(upb_ExtensionRegistry);
+pub type RawExtensionRegistry = NonNull<upb_ExtensionRegistry>;
diff --git a/rust/upb/lib.rs b/rust/upb/lib.rs
index 5698908..f557d1b 100644
--- a/rust/upb/lib.rs
+++ b/rust/upb/lib.rs
@@ -1,299 +1,38 @@
-use std::ptr::NonNull;
-use std::slice;
-
-mod opaque_pointee;
-use opaque_pointee::opaque_pointee;
-
 mod arena;
 pub use arena::{upb_Arena, Arena, RawArena};
 
-opaque_pointee!(upb_Message);
-pub type RawMessage = NonNull<upb_Message>;
+mod array;
+pub use array::{
+    upb_Array, upb_Array_Append, upb_Array_DataPtr, upb_Array_Get, upb_Array_GetMutable,
+    upb_Array_MutableDataPtr, upb_Array_New, upb_Array_Resize, upb_Array_Set, upb_Array_Size,
+    RawArray,
+};
 
-opaque_pointee!(upb_MiniTable);
-pub type RawMiniTable = NonNull<upb_MiniTable>;
+mod ctype;
+pub use ctype::CType;
 
-opaque_pointee!(upb_ExtensionRegistry);
-pub type RawExtensionRegistry = NonNull<upb_ExtensionRegistry>;
+mod extension_registry;
+pub use extension_registry::{upb_ExtensionRegistry, RawExtensionRegistry};
 
-opaque_pointee!(upb_Map);
-pub type RawMap = NonNull<upb_Map>;
+mod map;
+pub use map::{
+    upb_Map, upb_Map_Clear, upb_Map_Delete, upb_Map_Get, upb_Map_Insert, upb_Map_New, upb_Map_Next,
+    upb_Map_Size, MapInsertStatus, RawMap, __rust_proto_kUpb_Map_Begin,
+};
 
-opaque_pointee!(upb_Array);
-pub type RawArray = NonNull<upb_Array>;
+mod message;
+pub use message::{upb_Message, upb_Message_DeepClone, upb_Message_DeepCopy, RawMessage};
 
-extern "C" {
-    pub fn upb_Message_DeepCopy(
-        dst: RawMessage,
-        src: RawMessage,
-        mini_table: *const upb_MiniTable,
-        arena: RawArena,
-    );
+mod message_value;
+pub use message_value::{upb_MessageValue, upb_MutableMessageValue};
 
-    pub fn upb_Message_DeepClone(
-        m: RawMessage,
-        mini_table: *const upb_MiniTable,
-        arena: RawArena,
-    ) -> Option<RawMessage>;
-}
+mod mini_table;
+pub use mini_table::{upb_MiniTable, RawMiniTable};
 
-// LINT.IfChange(encode_status)
-#[repr(C)]
-#[derive(PartialEq, Eq, Copy, Clone)]
-pub enum EncodeStatus {
-    Ok = 0,
-    OutOfMemory = 1,
-    MaxDepthExceeded = 2,
-    MissingRequired = 3,
-}
-// LINT.ThenChange()
+mod opaque_pointee;
 
-// LINT.IfChange(decode_status)
-#[repr(C)]
-#[derive(PartialEq, Eq, Copy, Clone)]
-pub enum DecodeStatus {
-    Ok = 0,
-    Malformed = 1,
-    OutOfMemory = 2,
-    BadUtf8 = 3,
-    MaxDepthExceeded = 4,
-    MissingRequired = 5,
-    UnlinkedSubMessage = 6,
-}
-// LINT.ThenChange()
+mod string_view;
+pub use string_view::StringView;
 
-extern "C" {
-    pub fn upb_Encode(
-        msg: RawMessage,
-        mini_table: *const upb_MiniTable,
-        options: i32,
-        arena: RawArena,
-        buf: *mut *mut u8,
-        buf_size: *mut usize,
-    ) -> EncodeStatus;
-
-    pub fn upb_Decode(
-        buf: *const u8,
-        buf_size: usize,
-        msg: RawMessage,
-        mini_table: *const upb_MiniTable,
-        extreg: *const upb_ExtensionRegistry,
-        options: i32,
-        arena: RawArena,
-    ) -> DecodeStatus;
-}
-
-/// ABI compatible struct with upb_StringView.
-///
-/// Note that this has semantics similar to `std::string_view` in C++ and
-/// `&[u8]` in Rust, but is not ABI-compatible with either.
-///
-/// If `len` is 0, then `ptr` is allowed to be either null or dangling. C++
-/// considers a dangling 0-len `std::string_view` to be invalid, and Rust
-/// considers a `&[u8]` with a null data pointer to be invalid.
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct StringView {
-    /// Pointer to the first byte.
-    /// Borrows the memory.
-    pub ptr: *const u8,
-
-    /// Length of the `[u8]` pointed to by `ptr`.
-    pub len: usize,
-}
-
-impl StringView {
-    /// Unsafely dereference this slice.
-    ///
-    /// # Safety
-    /// - `self.ptr` must be dereferencable and immutable for `self.len` bytes
-    ///   for the lifetime `'a`. It can be null or dangling if `self.len == 0`.
-    pub unsafe fn as_ref<'a>(self) -> &'a [u8] {
-        if self.ptr.is_null() {
-            assert_eq!(self.len, 0, "Non-empty slice with null data pointer");
-            &[]
-        } else {
-            // SAFETY:
-            // - `ptr` is non-null
-            // - `ptr` is valid for `len` bytes as promised by the caller.
-            unsafe { slice::from_raw_parts(self.ptr, self.len) }
-        }
-    }
-}
-
-impl From<&[u8]> for StringView {
-    fn from(slice: &[u8]) -> Self {
-        Self { ptr: slice.as_ptr(), len: slice.len() }
-    }
-}
-
-// Transcribed from google3/third_party/upb/upb/message/value.h
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub union upb_MessageValue {
-    pub bool_val: bool,
-    pub float_val: std::ffi::c_float,
-    pub double_val: std::ffi::c_double,
-    pub uint32_val: u32,
-    pub int32_val: i32,
-    pub uint64_val: u64,
-    pub int64_val: i64,
-    // TODO: Replace this `RawMessage` with the const type.
-    pub array_val: Option<RawArray>,
-    pub map_val: Option<RawMap>,
-    pub msg_val: Option<RawMessage>,
-    pub str_val: StringView,
-
-    tagged_msg_val: *const std::ffi::c_void,
-}
-
-impl upb_MessageValue {
-    pub fn zeroed() -> Self {
-        // SAFETY: zero bytes is a valid representation for at least one value in the
-        // union (actually valid for all of them).
-        unsafe { std::mem::zeroed() }
-    }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy)]
-pub union upb_MutableMessageValue {
-    pub array: Option<RawArray>,
-    pub map: Option<RawMap>,
-    pub msg: Option<RawMessage>,
-}
-
-// Transcribed from google3/third_party/upb/upb/base/descriptor_constants.h
-#[repr(C)]
-#[allow(dead_code)]
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub enum CType {
-    Bool = 1,
-    Float = 2,
-    Int32 = 3,
-    UInt32 = 4,
-    Enum = 5,
-    Message = 6,
-    Double = 7,
-    Int64 = 8,
-    UInt64 = 9,
-    String = 10,
-    Bytes = 11,
-}
-
-extern "C" {
-    pub fn upb_Array_New(a: RawArena, r#type: CType) -> RawArray;
-    pub fn upb_Array_Size(arr: RawArray) -> usize;
-    pub fn upb_Array_Set(arr: RawArray, i: usize, val: upb_MessageValue);
-    pub fn upb_Array_Get(arr: RawArray, i: usize) -> upb_MessageValue;
-    pub fn upb_Array_Append(arr: RawArray, val: upb_MessageValue, arena: RawArena) -> bool;
-    pub fn upb_Array_Resize(arr: RawArray, size: usize, arena: RawArena) -> bool;
-    pub fn upb_Array_MutableDataPtr(arr: RawArray) -> *mut std::ffi::c_void;
-    pub fn upb_Array_DataPtr(arr: RawArray) -> *const std::ffi::c_void;
-    pub fn upb_Array_GetMutable(arr: RawArray, i: usize) -> upb_MutableMessageValue;
-}
-
-#[repr(C)]
-#[allow(dead_code)]
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub enum MapInsertStatus {
-    Inserted = 0,
-    Replaced = 1,
-    OutOfMemory = 2,
-}
-
-extern "C" {
-    pub fn upb_Map_New(arena: RawArena, key_type: CType, value_type: CType) -> RawMap;
-    pub fn upb_Map_Size(map: RawMap) -> usize;
-    pub fn upb_Map_Insert(
-        map: RawMap,
-        key: upb_MessageValue,
-        value: upb_MessageValue,
-        arena: RawArena,
-    ) -> MapInsertStatus;
-    pub fn upb_Map_Get(map: RawMap, key: upb_MessageValue, value: *mut upb_MessageValue) -> bool;
-    pub fn upb_Map_Delete(
-        map: RawMap,
-        key: upb_MessageValue,
-        removed_value: *mut upb_MessageValue,
-    ) -> bool;
-    pub fn upb_Map_Clear(map: RawMap);
-
-    pub static __rust_proto_kUpb_Map_Begin: usize;
-
-    pub fn upb_Map_Next(
-        map: RawMap,
-        key: *mut upb_MessageValue,
-        value: *mut upb_MessageValue,
-        iter: &mut usize,
-    ) -> bool;
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn array_ffi_test() {
-        // SAFETY: FFI unit test uses C API under expected patterns.
-        unsafe {
-            let arena = Arena::new();
-            let raw_arena = arena.raw();
-            let array = upb_Array_New(raw_arena, CType::Float);
-
-            assert!(upb_Array_Append(array, upb_MessageValue { float_val: 7.0 }, raw_arena));
-            assert!(upb_Array_Append(array, upb_MessageValue { float_val: 42.0 }, raw_arena));
-            assert_eq!(upb_Array_Size(array), 2);
-            assert!(matches!(upb_Array_Get(array, 1), upb_MessageValue { float_val: 42.0 }));
-
-            assert!(upb_Array_Resize(array, 3, raw_arena));
-            assert_eq!(upb_Array_Size(array), 3);
-            assert!(matches!(upb_Array_Get(array, 2), upb_MessageValue { float_val: 0.0 }));
-        }
-    }
-
-    #[test]
-    fn map_ffi_test() {
-        // SAFETY: FFI unit test uses C API under expected patterns.
-        unsafe {
-            let arena = Arena::new();
-            let raw_arena = arena.raw();
-            let map = upb_Map_New(raw_arena, CType::Bool, CType::Double);
-            assert_eq!(upb_Map_Size(map), 0);
-            assert_eq!(
-                upb_Map_Insert(
-                    map,
-                    upb_MessageValue { bool_val: true },
-                    upb_MessageValue { double_val: 2.0 },
-                    raw_arena
-                ),
-                MapInsertStatus::Inserted
-            );
-            assert_eq!(
-                upb_Map_Insert(
-                    map,
-                    upb_MessageValue { bool_val: true },
-                    upb_MessageValue { double_val: 3.0 },
-                    raw_arena,
-                ),
-                MapInsertStatus::Replaced,
-            );
-            assert_eq!(upb_Map_Size(map), 1);
-            upb_Map_Clear(map);
-            assert_eq!(upb_Map_Size(map), 0);
-            assert_eq!(
-                upb_Map_Insert(
-                    map,
-                    upb_MessageValue { bool_val: true },
-                    upb_MessageValue { double_val: 4.0 },
-                    raw_arena
-                ),
-                MapInsertStatus::Inserted
-            );
-
-            let mut out = upb_MessageValue::zeroed();
-            assert!(upb_Map_Get(map, upb_MessageValue { bool_val: true }, &mut out));
-            assert!(matches!(out, upb_MessageValue { double_val: 4.0 }));
-        }
-    }
-}
+mod wire;
+pub use wire::{upb_Decode, upb_Encode, DecodeStatus, EncodeStatus};
diff --git a/rust/upb/map.rs b/rust/upb/map.rs
new file mode 100644
index 0000000..14b8a7a
--- /dev/null
+++ b/rust/upb/map.rs
@@ -0,0 +1,91 @@
+use crate::opaque_pointee::opaque_pointee;
+use crate::{upb_MessageValue, CType, RawArena};
+use std::ptr::NonNull;
+
+opaque_pointee!(upb_Map);
+pub type RawMap = NonNull<upb_Map>;
+
+#[repr(C)]
+#[allow(dead_code)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub enum MapInsertStatus {
+    Inserted = 0,
+    Replaced = 1,
+    OutOfMemory = 2,
+}
+
+extern "C" {
+    pub static __rust_proto_kUpb_Map_Begin: usize;
+
+    pub fn upb_Map_New(arena: RawArena, key_type: CType, value_type: CType) -> RawMap;
+    pub fn upb_Map_Size(map: RawMap) -> usize;
+    pub fn upb_Map_Insert(
+        map: RawMap,
+        key: upb_MessageValue,
+        value: upb_MessageValue,
+        arena: RawArena,
+    ) -> MapInsertStatus;
+    pub fn upb_Map_Get(map: RawMap, key: upb_MessageValue, value: *mut upb_MessageValue) -> bool;
+    pub fn upb_Map_Delete(
+        map: RawMap,
+        key: upb_MessageValue,
+        removed_value: *mut upb_MessageValue,
+    ) -> bool;
+    pub fn upb_Map_Clear(map: RawMap);
+    pub fn upb_Map_Next(
+        map: RawMap,
+        key: *mut upb_MessageValue,
+        value: *mut upb_MessageValue,
+        iter: &mut usize,
+    ) -> bool;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn map_ffi_test() {
+        // SAFETY: FFI unit test uses C API under expected patterns.
+        unsafe {
+            let arena = crate::Arena::new();
+            let raw_arena = arena.raw();
+            let map = upb_Map_New(raw_arena, CType::Bool, CType::Double);
+            assert_eq!(upb_Map_Size(map), 0);
+            assert_eq!(
+                upb_Map_Insert(
+                    map,
+                    upb_MessageValue { bool_val: true },
+                    upb_MessageValue { double_val: 2.0 },
+                    raw_arena
+                ),
+                MapInsertStatus::Inserted
+            );
+            assert_eq!(
+                upb_Map_Insert(
+                    map,
+                    upb_MessageValue { bool_val: true },
+                    upb_MessageValue { double_val: 3.0 },
+                    raw_arena,
+                ),
+                MapInsertStatus::Replaced,
+            );
+            assert_eq!(upb_Map_Size(map), 1);
+            upb_Map_Clear(map);
+            assert_eq!(upb_Map_Size(map), 0);
+            assert_eq!(
+                upb_Map_Insert(
+                    map,
+                    upb_MessageValue { bool_val: true },
+                    upb_MessageValue { double_val: 4.0 },
+                    raw_arena
+                ),
+                MapInsertStatus::Inserted
+            );
+
+            let mut out = upb_MessageValue::zeroed();
+            assert!(upb_Map_Get(map, upb_MessageValue { bool_val: true }, &mut out));
+            assert!(matches!(out, upb_MessageValue { double_val: 4.0 }));
+        }
+    }
+}
diff --git a/rust/upb/message.rs b/rust/upb/message.rs
new file mode 100644
index 0000000..2a9fe91
--- /dev/null
+++ b/rust/upb/message.rs
@@ -0,0 +1,21 @@
+use crate::opaque_pointee::opaque_pointee;
+use crate::{upb_MiniTable, RawArena};
+use std::ptr::NonNull;
+
+opaque_pointee!(upb_Message);
+pub type RawMessage = NonNull<upb_Message>;
+
+extern "C" {
+    pub fn upb_Message_DeepCopy(
+        dst: RawMessage,
+        src: RawMessage,
+        mini_table: *const upb_MiniTable,
+        arena: RawArena,
+    );
+
+    pub fn upb_Message_DeepClone(
+        m: RawMessage,
+        mini_table: *const upb_MiniTable,
+        arena: RawArena,
+    ) -> Option<RawMessage>;
+}
diff --git a/rust/upb/message_value.rs b/rust/upb/message_value.rs
new file mode 100644
index 0000000..3838010
--- /dev/null
+++ b/rust/upb/message_value.rs
@@ -0,0 +1,37 @@
+use crate::{RawArray, RawMap, RawMessage, StringView};
+
+// Transcribed from google3/third_party/upb/upb/message/value.h
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub union upb_MessageValue {
+    pub bool_val: bool,
+    pub float_val: std::ffi::c_float,
+    pub double_val: std::ffi::c_double,
+    pub uint32_val: u32,
+    pub int32_val: i32,
+    pub uint64_val: u64,
+    pub int64_val: i64,
+    // TODO: Replace this `RawMessage` with the const type.
+    pub array_val: Option<RawArray>,
+    pub map_val: Option<RawMap>,
+    pub msg_val: Option<RawMessage>,
+    pub str_val: StringView,
+
+    tagged_msg_val: *const std::ffi::c_void,
+}
+
+impl upb_MessageValue {
+    pub fn zeroed() -> Self {
+        // SAFETY: zero bytes is a valid representation for at least one value in the
+        // union (actually valid for all of them).
+        unsafe { std::mem::zeroed() }
+    }
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub union upb_MutableMessageValue {
+    pub array: Option<RawArray>,
+    pub map: Option<RawMap>,
+    pub msg: Option<RawMessage>,
+}
diff --git a/rust/upb/mini_table.rs b/rust/upb/mini_table.rs
new file mode 100644
index 0000000..dc704ca
--- /dev/null
+++ b/rust/upb/mini_table.rs
@@ -0,0 +1,5 @@
+use crate::opaque_pointee::opaque_pointee;
+use std::ptr::NonNull;
+
+opaque_pointee!(upb_MiniTable);
+pub type RawMiniTable = NonNull<upb_MiniTable>;
diff --git a/rust/upb/string_view.rs b/rust/upb/string_view.rs
new file mode 100644
index 0000000..029c599
--- /dev/null
+++ b/rust/upb/string_view.rs
@@ -0,0 +1,43 @@
+/// ABI compatible struct with upb_StringView.
+///
+/// Note that this has semantics similar to `std::string_view` in C++ and
+/// `&[u8]` in Rust, but is not ABI-compatible with either.
+///
+/// If `len` is 0, then `ptr` is allowed to be either null or dangling. C++
+/// considers a dangling 0-len `std::string_view` to be invalid, and Rust
+/// considers a `&[u8]` with a null data pointer to be invalid.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct StringView {
+    /// Pointer to the first byte.
+    /// Borrows the memory.
+    pub ptr: *const u8,
+
+    /// Length of the `[u8]` pointed to by `ptr`.
+    pub len: usize,
+}
+
+impl StringView {
+    /// Unsafely dereference this slice.
+    ///
+    /// # Safety
+    /// - `self.ptr` must be dereferencable and immutable for `self.len` bytes
+    ///   for the lifetime `'a`. It can be null or dangling if `self.len == 0`.
+    pub unsafe fn as_ref<'a>(self) -> &'a [u8] {
+        if self.ptr.is_null() {
+            assert_eq!(self.len, 0, "Non-empty slice with null data pointer");
+            &[]
+        } else {
+            // SAFETY:
+            // - `ptr` is non-null
+            // - `ptr` is valid for `len` bytes as promised by the caller.
+            unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
+        }
+    }
+}
+
+impl From<&[u8]> for StringView {
+    fn from(slice: &[u8]) -> Self {
+        Self { ptr: slice.as_ptr(), len: slice.len() }
+    }
+}
diff --git a/rust/upb/wire.rs b/rust/upb/wire.rs
new file mode 100644
index 0000000..2b68145
--- /dev/null
+++ b/rust/upb/wire.rs
@@ -0,0 +1,47 @@
+use crate::{upb_ExtensionRegistry, upb_MiniTable, RawArena, RawMessage};
+
+// LINT.IfChange(encode_status)
+#[repr(C)]
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub enum EncodeStatus {
+    Ok = 0,
+    OutOfMemory = 1,
+    MaxDepthExceeded = 2,
+    MissingRequired = 3,
+}
+// LINT.ThenChange()
+
+// LINT.IfChange(decode_status)
+#[repr(C)]
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub enum DecodeStatus {
+    Ok = 0,
+    Malformed = 1,
+    OutOfMemory = 2,
+    BadUtf8 = 3,
+    MaxDepthExceeded = 4,
+    MissingRequired = 5,
+    UnlinkedSubMessage = 6,
+}
+// LINT.ThenChange()
+
+extern "C" {
+    pub fn upb_Encode(
+        msg: RawMessage,
+        mini_table: *const upb_MiniTable,
+        options: i32,
+        arena: RawArena,
+        buf: *mut *mut u8,
+        buf_size: *mut usize,
+    ) -> EncodeStatus;
+
+    pub fn upb_Decode(
+        buf: *const u8,
+        buf_size: usize,
+        msg: RawMessage,
+        mini_table: *const upb_MiniTable,
+        extreg: *const upb_ExtensionRegistry,
+        options: i32,
+        arena: RawArena,
+    ) -> DecodeStatus;
+}