|
|
|
// 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::{upb_ExtensionRegistry, upb_MiniTable, Arena, RawArena, RawMessage};
|
|
|
|
|
|
|
|
// LINT.IfChange(encode_status)
|
|
|
|
#[repr(C)]
|
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
|
|
|
pub enum EncodeStatus {
|
|
|
|
Ok = 0,
|
|
|
|
OutOfMemory = 1,
|
|
|
|
MaxDepthExceeded = 2,
|
|
|
|
MissingRequired = 3,
|
|
|
|
}
|
|
|
|
// LINT.ThenChange()
|
|
|
|
|
|
|
|
// LINT.IfChange(decode_status)
|
|
|
|
#[repr(C)]
|
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
|
|
|
pub enum DecodeStatus {
|
|
|
|
Ok = 0,
|
|
|
|
Malformed = 1,
|
|
|
|
OutOfMemory = 2,
|
|
|
|
BadUtf8 = 3,
|
|
|
|
MaxDepthExceeded = 4,
|
|
|
|
MissingRequired = 5,
|
|
|
|
UnlinkedSubMessage = 6,
|
|
|
|
}
|
|
|
|
// LINT.ThenChange()
|
|
|
|
|
|
|
|
#[repr(i32)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
enum DecodeOption {
|
|
|
|
AliasString = 1,
|
|
|
|
CheckRequired = 2,
|
|
|
|
ExperimentalAllowUnlinked = 4,
|
|
|
|
AlwaysValidateUtf8 = 8,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If Err, then EncodeStatus != Ok.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg` must be associated with `mini_table`.
|
|
|
|
pub unsafe fn encode(
|
|
|
|
msg: RawMessage,
|
|
|
|
mini_table: *const upb_MiniTable,
|
|
|
|
) -> Result<Vec<u8>, EncodeStatus> {
|
|
|
|
let arena = Arena::new();
|
|
|
|
let mut buf: *mut u8 = core::ptr::null_mut();
|
|
|
|
let mut len = 0usize;
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
// - `mini_table` is the one associated with `msg`.
|
|
|
|
// - `buf` and `buf_size` are legally writable.
|
|
|
|
let status = unsafe { upb_Encode(msg, 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Decodes into the provided message (merge semantics). If Err, then
|
|
|
|
/// DecodeStatus != Ok.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// - `msg` must be mutable.
|
|
|
|
/// - `msg` must be associated with `mini_table`.
|
|
|
|
pub unsafe fn decode(
|
|
|
|
buf: &[u8],
|
|
|
|
msg: RawMessage,
|
|
|
|
mini_table: *const upb_MiniTable,
|
|
|
|
arena: &Arena,
|
|
|
|
) -> Result<(), DecodeStatus> {
|
|
|
|
let len = buf.len();
|
|
|
|
let buf = buf.as_ptr();
|
|
|
|
let options = DecodeOption::CheckRequired as i32;
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
// - `mini_table` is the one associated with `msg`
|
|
|
|
// - `buf` is legally readable for at least `buf_size` bytes.
|
|
|
|
// - `extreg` is null.
|
|
|
|
let status =
|
|
|
|
unsafe { upb_Decode(buf, len, msg, mini_table, core::ptr::null(), options, arena.raw()) };
|
|
|
|
match status {
|
|
|
|
DecodeStatus::Ok => Ok(()),
|
|
|
|
_ => Err(status),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
// SAFETY:
|
|
|
|
// - `mini_table` is the one associated with `msg`
|
|
|
|
// - `buf` and `buf_size` are legally writable.
|
|
|
|
pub fn upb_Encode(
|
|
|
|
msg: RawMessage,
|
|
|
|
mini_table: *const upb_MiniTable,
|
|
|
|
options: i32,
|
|
|
|
arena: RawArena,
|
|
|
|
buf: *mut *mut u8,
|
|
|
|
buf_size: *mut usize,
|
|
|
|
) -> EncodeStatus;
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
// - `mini_table` is the one associated with `msg`
|
|
|
|
// - `buf` is legally readable for at least `buf_size` bytes.
|
|
|
|
// - `extreg` is either null or points at a valid upb_ExtensionRegistry.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use googletest::gtest;
|
|
|
|
|
|
|
|
#[gtest]
|
|
|
|
fn assert_wire_linked() {
|
|
|
|
use crate::assert_linked;
|
|
|
|
assert_linked!(upb_Encode);
|
|
|
|
assert_linked!(upb_Decode);
|
|
|
|
}
|
|
|
|
}
|