// 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, EncodeStatus> { let arena = Arena::new(); let mut buf: *mut u8 = std::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 { &*std::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, std::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; }