Change `upb` crate source to not use std or alloc
PiperOrigin-RevId: 671865731
This commit is contained in:
Родитель
e3f37a2eb0
Коммит
b35d4bad3c
20
rust/upb.rs
20
rust/upb.rs
|
@ -13,7 +13,6 @@ use crate::{
|
|||
Proxied, ProxiedInMapValue, ProxiedInRepeated, Repeated, RepeatedMut, RepeatedView, View,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use std::alloc::Layout;
|
||||
use std::mem::{size_of, ManuallyDrop, MaybeUninit};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
|
@ -133,21 +132,6 @@ impl<'msg> MutatorMessageRef<'msg> {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_bytes_in_arena<'msg>(arena: &'msg Arena, val: &'msg [u8]) -> &'msg [u8] {
|
||||
// SAFETY: the alignment of `[u8]` is less than `UPB_MALLOC_ALIGN`.
|
||||
let new_alloc = unsafe { arena.alloc(Layout::for_value(val)) };
|
||||
debug_assert_eq!(new_alloc.len(), val.len());
|
||||
|
||||
let start: *mut u8 = new_alloc.as_mut_ptr().cast();
|
||||
// SAFETY:
|
||||
// - `new_alloc` is writeable for `val.len()` bytes.
|
||||
// - After the copy, `new_alloc` is initialized for `val.len()` bytes.
|
||||
unsafe {
|
||||
val.as_ptr().copy_to_nonoverlapping(start, val.len());
|
||||
&*(new_alloc as *mut _ as *mut [u8])
|
||||
}
|
||||
}
|
||||
|
||||
/// Kernel-specific owned `string` and `bytes` field type.
|
||||
#[doc(hidden)]
|
||||
pub struct InnerProtoString(OwnedArenaBox<[u8]>);
|
||||
|
@ -167,7 +151,7 @@ impl InnerProtoString {
|
|||
impl From<&[u8]> for InnerProtoString {
|
||||
fn from(val: &[u8]) -> InnerProtoString {
|
||||
let arena = Arena::new();
|
||||
let in_arena_copy = arena.copy_slice_in(val);
|
||||
let in_arena_copy = arena.copy_slice_in(val).unwrap();
|
||||
// SAFETY:
|
||||
// - `in_arena_copy` is valid slice that will live for `arena`'s lifetime and
|
||||
// this is the only reference in the program to it.
|
||||
|
@ -354,7 +338,7 @@ macro_rules! impl_repeated_bytes {
|
|||
len
|
||||
);
|
||||
for (src_ptr, dest_ptr) in src_ptrs.iter().zip(dest_ptrs) {
|
||||
*dest_ptr = copy_bytes_in_arena(&arena, src_ptr.as_ref()).into();
|
||||
*dest_ptr = arena.copy_slice_in(src_ptr.as_ref()).unwrap().into();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use super::opaque_pointee::opaque_pointee;
|
||||
use std::alloc::{self, Layout};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{align_of, MaybeUninit};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
use core::cell::UnsafeCell;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{align_of, align_of_val, size_of_val, MaybeUninit};
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::slice;
|
||||
|
||||
opaque_pointee!(upb_Arena);
|
||||
pub type RawArena = NonNull<upb_Arena>;
|
||||
|
@ -79,75 +78,85 @@ impl Arena {
|
|||
self.raw
|
||||
}
|
||||
|
||||
/// Allocates some memory on the arena.
|
||||
/// Allocates some memory on the arena. Returns None if the allocation
|
||||
/// failed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `layout`'s alignment must be less than `UPB_MALLOC_ALIGN`.
|
||||
/// - `align` must be less than `UPB_MALLOC_ALIGN`.
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
#[inline]
|
||||
pub unsafe fn alloc(&self, layout: Layout) -> &mut [MaybeUninit<u8>] {
|
||||
debug_assert!(layout.align() <= UPB_MALLOC_ALIGN);
|
||||
pub unsafe fn alloc(&self, size: usize, align: usize) -> Option<&mut [MaybeUninit<u8>]> {
|
||||
debug_assert!(align <= UPB_MALLOC_ALIGN);
|
||||
// SAFETY: `self.raw` is a valid UPB arena
|
||||
let ptr = unsafe { upb_Arena_Malloc(self.raw, layout.size()) };
|
||||
if ptr.is_null() {
|
||||
alloc::handle_alloc_error(layout);
|
||||
}
|
||||
let ptr = unsafe { upb_Arena_Malloc(self.raw, size) };
|
||||
|
||||
// SAFETY:
|
||||
// - `upb_Arena_Malloc` promises that if the return pointer is non-null, it is
|
||||
// dereferencable for `size` bytes and has an alignment of `UPB_MALLOC_ALIGN`
|
||||
// until the arena is destroyed.
|
||||
// - `[MaybeUninit<u8>]` has no alignment requirement, and `ptr` is aligned to a
|
||||
// `UPB_MALLOC_ALIGN` boundary.
|
||||
unsafe { slice::from_raw_parts_mut(ptr.cast(), layout.size()) }
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
// SAFETY:
|
||||
// - `upb_Arena_Malloc` promises that if the return pointer is non-null, it is
|
||||
// dereferencable for `size` bytes and has an alignment of `UPB_MALLOC_ALIGN`
|
||||
// until the arena is destroyed.
|
||||
// - `[MaybeUninit<u8>]` has no alignment requirement, and `ptr` is aligned to a
|
||||
// `UPB_MALLOC_ALIGN` boundary.
|
||||
Some(unsafe { slice::from_raw_parts_mut(ptr.cast(), size) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as alloc() but panics if `layout.align() > UPB_MALLOC_ALIGN`.
|
||||
/// Same as alloc() but panics if `align > UPB_MALLOC_ALIGN`.
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
#[inline]
|
||||
pub fn checked_alloc(&self, layout: Layout) -> &mut [MaybeUninit<u8>] {
|
||||
assert!(layout.align() <= UPB_MALLOC_ALIGN);
|
||||
// SAFETY: layout.align() <= UPB_MALLOC_ALIGN asserted.
|
||||
unsafe { self.alloc(layout) }
|
||||
pub fn checked_alloc(&self, size: usize, align: usize) -> Option<&mut [MaybeUninit<u8>]> {
|
||||
assert!(align <= UPB_MALLOC_ALIGN);
|
||||
// SAFETY: align <= UPB_MALLOC_ALIGN asserted.
|
||||
unsafe { self.alloc(size, align) }
|
||||
}
|
||||
|
||||
/// Copies the T into this arena and returns a pointer to the T data inside
|
||||
/// the arena.
|
||||
pub fn copy_in<'a, T: Copy>(&'a self, data: &T) -> &'a T {
|
||||
let layout = Layout::for_value(data);
|
||||
let alloc = self.checked_alloc(layout);
|
||||
/// the arena. Returns None if the allocation failed.
|
||||
pub fn copy_in<'a, T: Copy>(&'a self, data: &T) -> Option<&'a T> {
|
||||
let size = size_of_val(data);
|
||||
let align = align_of_val(data);
|
||||
|
||||
// SAFETY:
|
||||
// - alloc is valid for `layout.len()` bytes and is the uninit bytes are written
|
||||
// to not read from until written.
|
||||
// - T is copy so copying the bytes of the value is sound.
|
||||
unsafe {
|
||||
let alloc = alloc.as_mut_ptr().cast::<MaybeUninit<T>>();
|
||||
// let data = (data as *const T).cast::<MaybeUninit<T>>();
|
||||
(*alloc).write(*data)
|
||||
}
|
||||
self.checked_alloc(size, align).map(|alloc| {
|
||||
// SAFETY:
|
||||
// - alloc is valid for `size` bytes and is the uninit bytes are written to not
|
||||
// read from until written.
|
||||
// - T is copy so copying the bytes of the value is sound.
|
||||
unsafe {
|
||||
let alloc = alloc.as_mut_ptr().cast::<MaybeUninit<T>>();
|
||||
&*(*alloc).write(*data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn copy_str_in<'a>(&'a self, s: &str) -> &'a str {
|
||||
let copied_bytes = self.copy_slice_in(s.as_bytes());
|
||||
// SAFETY: `copied_bytes` has same contents as `s` and so must meet &str
|
||||
// criteria.
|
||||
unsafe { std::str::from_utf8_unchecked(copied_bytes) }
|
||||
/// Copies the str into this arena and returns a pointer to the T data
|
||||
/// inside the arena. Returns None if the allocation failed.
|
||||
pub fn copy_str_in<'a>(&'a self, s: &str) -> Option<&'a str> {
|
||||
self.copy_slice_in(s.as_bytes()).map(|copied_bytes| {
|
||||
// SAFETY: `copied_bytes` has same contents as `s` and so must meet &str
|
||||
// criteria.
|
||||
unsafe { core::str::from_utf8_unchecked(copied_bytes) }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn copy_slice_in<'a, T: Copy>(&'a self, data: &[T]) -> &'a [T] {
|
||||
let layout = Layout::for_value(data);
|
||||
let alloc: *mut T = self.checked_alloc(layout).as_mut_ptr().cast();
|
||||
|
||||
// SAFETY:
|
||||
// - uninit_alloc is valid for `layout.len()` bytes and is the uninit bytes are
|
||||
// written to not read from until written.
|
||||
// - T is copy so copying the bytes of the values is sound.
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), alloc, data.len());
|
||||
slice::from_raw_parts_mut(alloc, data.len())
|
||||
}
|
||||
/// Copies the slice into this arena and returns a pointer to the T data
|
||||
/// inside the arena. Returns None if the allocation failed.
|
||||
pub fn copy_slice_in<'a, T: Copy>(&'a self, data: &[T]) -> Option<&'a [T]> {
|
||||
let size = size_of_val(data);
|
||||
let align = align_of_val(data);
|
||||
self.checked_alloc(size, align).map(|alloc| {
|
||||
let alloc: *mut T = alloc.as_mut_ptr().cast();
|
||||
// SAFETY:
|
||||
// - uninit_alloc is valid for `layout.len()` bytes and is the uninit bytes are
|
||||
// written to not read from until written.
|
||||
// - T is copy so copying the bytes of the values is sound.
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(data.as_ptr(), alloc, data.len());
|
||||
slice::from_raw_parts(alloc, data.len())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Fuse two arenas so they share the same lifetime.
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use super::opaque_pointee::opaque_pointee;
|
||||
use super::{upb_MessageValue, upb_MutableMessageValue, CType, RawArena};
|
||||
use std::ptr::NonNull;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
opaque_pointee!(upb_Array);
|
||||
pub type RawArray = NonNull<upb_Array>;
|
||||
|
@ -20,8 +20,8 @@ extern "C" {
|
|||
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_Reserve(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_MutableDataPtr(arr: RawArray) -> *mut core::ffi::c_void;
|
||||
pub fn upb_Array_DataPtr(arr: RawArray) -> *const core::ffi::c_void;
|
||||
pub fn upb_Array_GetMutable(arr: RawArray, i: usize) -> upb_MutableMessageValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use super::opaque_pointee::opaque_pointee;
|
||||
use std::ptr::NonNull;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
opaque_pointee!(upb_ExtensionRegistry);
|
||||
pub type RawExtensionRegistry = NonNull<upb_ExtensionRegistry>;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
use super::opaque_pointee::opaque_pointee;
|
||||
use super::{upb_MessageValue, CType, RawArena};
|
||||
use std::ptr::NonNull;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
opaque_pointee!(upb_Map);
|
||||
pub type RawMap = NonNull<upb_Map>;
|
||||
|
|
|
@ -10,7 +10,7 @@ use super::{
|
|||
upb_ExtensionRegistry, upb_MiniTable, upb_MiniTableField, RawArena, RawArray, RawMap,
|
||||
StringView,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
opaque_pointee!(upb_Message);
|
||||
pub type RawMessage = NonNull<upb_Message>;
|
||||
|
@ -215,7 +215,7 @@ extern "C" {
|
|||
pub fn upb_Message_SetBaseField(
|
||||
m: RawMessage,
|
||||
f: *const upb_MiniTableField,
|
||||
val: *const std::ffi::c_void,
|
||||
val: *const core::ffi::c_void,
|
||||
);
|
||||
|
||||
/// # Safety
|
||||
|
|
|
@ -12,8 +12,8 @@ use super::{RawArray, RawMap, RawMessage, StringView};
|
|||
#[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 float_val: core::ffi::c_float,
|
||||
pub double_val: core::ffi::c_double,
|
||||
pub uint32_val: u32,
|
||||
pub int32_val: i32,
|
||||
pub uint64_val: u64,
|
||||
|
@ -24,14 +24,14 @@ pub union upb_MessageValue {
|
|||
pub msg_val: Option<RawMessage>,
|
||||
pub str_val: StringView,
|
||||
|
||||
tagged_msg_val: *const std::ffi::c_void,
|
||||
tagged_msg_val: *const core::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() }
|
||||
unsafe { core::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use super::opaque_pointee::opaque_pointee;
|
||||
use std::ptr::NonNull;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
opaque_pointee!(upb_MiniTable);
|
||||
pub type RawMiniTable = NonNull<upb_MiniTable>;
|
||||
|
|
|
@ -15,7 +15,7 @@ macro_rules! opaque_pointee {
|
|||
#[repr(C)]
|
||||
pub struct $name {
|
||||
_data: [u8; 0],
|
||||
_marker: std::marker::PhantomData<(*mut u8, std::marker::PhantomPinned)>,
|
||||
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
use super::Arena;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr::NonNull;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// An 'owned' T, similar to a Box<T> where the T is data
|
||||
/// held in a upb Arena. By holding the data pointer and a corresponding arena
|
||||
|
@ -18,7 +18,7 @@ use std::ptr::NonNull;
|
|||
/// inside `arena`. This avoids typical concerns of self-referential data
|
||||
/// structures because `arena` modifications (other than drop) will never
|
||||
/// invalidate `data`, and `data` and `arena` are both behind indirections which
|
||||
/// avoids any concern with std::mem::swap.
|
||||
/// avoids any concern with core::mem::swap.
|
||||
pub struct OwnedArenaBox<T: ?Sized + 'static> {
|
||||
data: NonNull<T>,
|
||||
arena: Arena,
|
||||
|
@ -87,7 +87,7 @@ impl<T: Debug + 'static> Debug for OwnedArenaBox<T> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::str;
|
||||
use core::str;
|
||||
|
||||
#[test]
|
||||
fn test_byte_slice_pointer_roundtrip() {
|
||||
|
@ -101,7 +101,7 @@ mod tests {
|
|||
fn test_alloc_str_roundtrip() {
|
||||
let arena = Arena::new();
|
||||
let s: &str = "Hello";
|
||||
let arena_alloc_str: NonNull<str> = arena.copy_str_in(s).into();
|
||||
let arena_alloc_str: NonNull<str> = arena.copy_str_in(s).unwrap().into();
|
||||
let owned_data = unsafe { OwnedArenaBox::new(arena_alloc_str, arena) };
|
||||
assert_eq!(&*owned_data, s);
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_sized_type_roundtrip() {
|
||||
let arena = Arena::new();
|
||||
let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).into();
|
||||
let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).unwrap().into();
|
||||
let mut owned_data = unsafe { OwnedArenaBox::new(arena_alloc_u32, arena) };
|
||||
assert_eq!(*owned_data, 7);
|
||||
*owned_data = 8;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
/// ABI compatible struct with upb_StringView.
|
||||
///
|
||||
/// Note that this has semantics similar to `std::string_view` in C++ and
|
||||
/// Note that this has semantics similar to `core::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 dangling 0-len `core::string_view` to be invalid, and Rust
|
||||
/// considers a `&[u8]` with a null data pointer to be invalid.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -38,7 +38,7 @@ impl StringView {
|
|||
// 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) }
|
||||
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ pub unsafe fn debug_string(msg: RawMessage, mt: *const upb_MiniTable) -> String
|
|||
// `mt`
|
||||
// - `buf` is nullptr and `buf_len` is 0
|
||||
let len =
|
||||
unsafe { upb_DebugString(msg, mt, Options::NoSortMaps as i32, std::ptr::null_mut(), 0) };
|
||||
unsafe { upb_DebugString(msg, mt, Options::NoSortMaps as i32, core::ptr::null_mut(), 0) };
|
||||
assert!(len < isize::MAX as usize);
|
||||
// +1 for the trailing NULL
|
||||
let mut buf = vec![0u8; len + 1];
|
||||
|
|
|
@ -50,7 +50,7 @@ pub unsafe fn encode(
|
|||
mini_table: *const upb_MiniTable,
|
||||
) -> Result<Vec<u8>, EncodeStatus> {
|
||||
let arena = Arena::new();
|
||||
let mut buf: *mut u8 = std::ptr::null_mut();
|
||||
let mut buf: *mut u8 = core::ptr::null_mut();
|
||||
let mut len = 0usize;
|
||||
|
||||
// SAFETY:
|
||||
|
@ -61,7 +61,7 @@ pub unsafe fn encode(
|
|||
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())
|
||||
Ok(unsafe { &*core::ptr::slice_from_raw_parts(buf, len) }.to_vec())
|
||||
} else {
|
||||
Err(status)
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ pub unsafe fn decode(
|
|||
// - `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()) };
|
||||
unsafe { upb_Decode(buf, len, msg, mini_table, core::ptr::null(), options, arena.raw()) };
|
||||
match status {
|
||||
DecodeStatus::Ok => Ok(()),
|
||||
_ => Err(status),
|
||||
|
|
Загрузка…
Ссылка в новой задаче