1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2024 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 use super::{upb_ExtensionRegistry, upb_MiniTable, Arena, RawArena, RawMessage};
9
10 // LINT.IfChange(encode_status)
11 #[repr(C)]
12 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
13 pub enum EncodeStatus {
14 Ok = 0,
15 OutOfMemory = 1,
16 MaxDepthExceeded = 2,
17 MissingRequired = 3,
18 }
19 // LINT.ThenChange()
20
21 // LINT.IfChange(decode_status)
22 #[repr(C)]
23 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
24 pub enum DecodeStatus {
25 Ok = 0,
26 Malformed = 1,
27 OutOfMemory = 2,
28 BadUtf8 = 3,
29 MaxDepthExceeded = 4,
30 MissingRequired = 5,
31 UnlinkedSubMessage = 6,
32 }
33 // LINT.ThenChange()
34
35 #[repr(i32)]
36 #[allow(dead_code)]
37 enum DecodeOption {
38 AliasString = 1,
39 CheckRequired = 2,
40 ExperimentalAllowUnlinked = 4,
41 AlwaysValidateUtf8 = 8,
42 }
43
44 /// If Err, then EncodeStatus != Ok.
45 ///
46 /// # Safety
47 /// - `msg` must be associated with `mini_table`.
encode( msg: RawMessage, mini_table: *const upb_MiniTable, ) -> Result<Vec<u8>, EncodeStatus>48 pub unsafe fn encode(
49 msg: RawMessage,
50 mini_table: *const upb_MiniTable,
51 ) -> Result<Vec<u8>, EncodeStatus> {
52 let arena = Arena::new();
53 let mut buf: *mut u8 = core::ptr::null_mut();
54 let mut len = 0usize;
55
56 // SAFETY:
57 // - `mini_table` is the one associated with `msg`.
58 // - `buf` and `buf_size` are legally writable.
59 let status = unsafe { upb_Encode(msg, mini_table, 0, arena.raw(), &mut buf, &mut len) };
60
61 if status == EncodeStatus::Ok {
62 assert!(!buf.is_null()); // EncodeStatus Ok should never return NULL data, even for len=0.
63 // SAFETY: upb guarantees that `buf` is valid to read for `len`.
64 Ok(unsafe { &*core::ptr::slice_from_raw_parts(buf, len) }.to_vec())
65 } else {
66 Err(status)
67 }
68 }
69
70 /// Decodes into the provided message (merge semantics). If Err, then
71 /// DecodeStatus != Ok.
72 ///
73 /// # Safety
74 /// - `msg` must be mutable.
75 /// - `msg` must be associated with `mini_table`.
decode( buf: &[u8], msg: RawMessage, mini_table: *const upb_MiniTable, arena: &Arena, ) -> Result<(), DecodeStatus>76 pub unsafe fn decode(
77 buf: &[u8],
78 msg: RawMessage,
79 mini_table: *const upb_MiniTable,
80 arena: &Arena,
81 ) -> Result<(), DecodeStatus> {
82 let len = buf.len();
83 let buf = buf.as_ptr();
84 let options = DecodeOption::CheckRequired as i32;
85
86 // SAFETY:
87 // - `mini_table` is the one associated with `msg`
88 // - `buf` is legally readable for at least `buf_size` bytes.
89 // - `extreg` is null.
90 let status =
91 unsafe { upb_Decode(buf, len, msg, mini_table, core::ptr::null(), options, arena.raw()) };
92 match status {
93 DecodeStatus::Ok => Ok(()),
94 _ => Err(status),
95 }
96 }
97
98 extern "C" {
99 // SAFETY:
100 // - `mini_table` is the one associated with `msg`
101 // - `buf` and `buf_size` are legally writable.
upb_Encode( msg: RawMessage, mini_table: *const upb_MiniTable, options: i32, arena: RawArena, buf: *mut *mut u8, buf_size: *mut usize, ) -> EncodeStatus102 pub fn upb_Encode(
103 msg: RawMessage,
104 mini_table: *const upb_MiniTable,
105 options: i32,
106 arena: RawArena,
107 buf: *mut *mut u8,
108 buf_size: *mut usize,
109 ) -> EncodeStatus;
110
111 // SAFETY:
112 // - `mini_table` is the one associated with `msg`
113 // - `buf` is legally readable for at least `buf_size` bytes.
114 // - `extreg` is either null or points at a valid upb_ExtensionRegistry.
upb_Decode( buf: *const u8, buf_size: usize, msg: RawMessage, mini_table: *const upb_MiniTable, extreg: *const upb_ExtensionRegistry, options: i32, arena: RawArena, ) -> DecodeStatus115 pub fn upb_Decode(
116 buf: *const u8,
117 buf_size: usize,
118 msg: RawMessage,
119 mini_table: *const upb_MiniTable,
120 extreg: *const upb_ExtensionRegistry,
121 options: i32,
122 arena: RawArena,
123 ) -> DecodeStatus;
124 }
125
126 #[cfg(test)]
127 mod tests {
128 use super::*;
129 use googletest::gtest;
130
131 #[gtest]
assert_wire_linked()132 fn assert_wire_linked() {
133 use crate::assert_linked;
134 assert_linked!(upb_Encode);
135 assert_linked!(upb_Decode);
136 }
137 }
138