| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2024 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 | |
| use super::sys::mini_table::extension_registry::upb_ExtensionRegistry; | |
| use super::sys::wire::wire::{upb_ByteSize, upb_Decode, upb_Encode, DecodeStatus, EncodeStatus}; | |
| use super::{Arena, AssociatedMiniTable, MessagePtr}; | |
| /// Contains the decode options that can be passed to `decode_with_options`. | |
| #[allow(unused)] // FFI constants. | |
| pub mod decode_options { | |
| // LINT.IfChange(decode_option) | |
| pub const ALIAS_STRING: i32 = 1; | |
| pub const CHECK_REQUIRED: i32 = 2; | |
| pub const EXPERIMENTAL_ALLOW_UNLINKED: i32 = 4; | |
| pub const ALWAYS_VALIDATE_UTF8: i32 = 8; | |
| // LINT.ThenChange() | |
| } | |
| /// If Err, then EncodeStatus != Ok. | |
| pub fn encode<T: AssociatedMiniTable>(msg: MessagePtr<T>) -> Result<Vec<u8>, EncodeStatus> { | |
| let arena = Arena::new(); | |
| let mut buf: *mut u8 = core::ptr::null_mut(); | |
| let mut len = 0usize; | |
| // SAFETY: | |
| // - `T::mini_table()` is the one associated with `msg`. | |
| // - `buf` and `buf_size` are legally writable. | |
| let status = | |
| unsafe { upb_Encode(msg.raw(), T::mini_table(), 0, arena.raw(), &mut buf, &mut len) }; | |
| if status == EncodeStatus::Ok { | |
| assert!(!buf.is_null()); // EncodeStatus Ok should never return NULL data, even for len=0. | |
| // SAFETY: upb guarantees that `buf` is valid to read for `len`. | |
| Ok(unsafe { &*core::ptr::slice_from_raw_parts(buf, len) }.to_vec()) | |
| } else { | |
| Err(status) | |
| } | |
| } | |
| /// Returns the serialized size of the message. | |
| pub fn byte_size<T: AssociatedMiniTable>(msg: MessagePtr<T>) -> usize { | |
| // SAFETY: | |
| // - `T::mini_table()` is the one associated with `msg`. | |
| // - `msg` is guaranteed live. | |
| unsafe { upb_ByteSize(msg.raw(), T::mini_table()) } | |
| } | |
| /// Decodes into the provided message (merge semantics). If Err, then | |
| /// DecodeStatus != Ok. | |
| /// | |
| /// Equivalent to `decode_with_options()` with the | |
| /// `decode_options::CHECK_REQUIRED` option set. | |
| /// | |
| /// # Safety | |
| /// - `msg` must be mutable. | |
| #[allow(unused)] // Not used yet. | |
| pub unsafe fn decode<T: AssociatedMiniTable>( | |
| buf: &[u8], | |
| msg: MessagePtr<T>, | |
| extreg: *const upb_ExtensionRegistry, | |
| arena: &Arena, | |
| ) -> Result<(), DecodeStatus> { | |
| // SAFETY: | |
| // - `msg` is mutable and is associated with `mini_table`. | |
| // - `decode_options::CHECK_REQUIRED` is a valid decode option. | |
| unsafe { decode_with_options(buf, msg, extreg, arena, decode_options::CHECK_REQUIRED) } | |
| } | |
| /// Decodes into the provided message (merge semantics). If Err, then | |
| /// DecodeStatus != Ok. | |
| /// | |
| /// # Safety | |
| /// - `msg` must be mutable. | |
| /// - `decode_options_bitmask` is a bitmask of constants from the `decode_options` module. | |
| pub unsafe fn decode_with_options<T: AssociatedMiniTable>( | |
| buf: &[u8], | |
| msg: MessagePtr<T>, | |
| extreg: *const upb_ExtensionRegistry, | |
| arena: &Arena, | |
| decode_options_bitmask: i32, | |
| ) -> Result<(), DecodeStatus> { | |
| let len = buf.len(); | |
| let buf = buf.as_ptr(); | |
| // SAFETY: | |
| // - `mini_table` is the one associated with `msg` | |
| // - `buf` is legally readable for at least `buf_size` bytes. | |
| // - `extreg` is null. | |
| // - `decode_options_bitmask` is a bitmask of constants from the `decode_options` module. | |
| let status = unsafe { | |
| upb_Decode( | |
| buf, | |
| len, | |
| msg.raw(), | |
| T::mini_table(), | |
| extreg, | |
| decode_options_bitmask, | |
| arena.raw(), | |
| ) | |
| }; | |
| match status { | |
| DecodeStatus::Ok => Ok(()), | |
| _ => Err(status), | |
| } | |
| } |