-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create the concept of 'owned data' in upb/rust as a generalization of…
… the upb.rs SerializedData (which is a arena + data for arbitrary types, both thin and wide ref types), use that for the wire parse/serialize path. PiperOrigin-RevId: 626012269
- Loading branch information
1 parent
5587559
commit 862d103
Showing
8 changed files
with
246 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
use crate::Arena; | ||
use std::fmt::{self, Debug}; | ||
use std::ops::{Deref, DerefMut}; | ||
use std::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 | ||
/// together the data liveness is be maintained. | ||
/// | ||
/// This struct is conceptually self-referential, where `data` points at memory | ||
/// 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. | ||
pub struct OwnedArenaBox<T: ?Sized + 'static> { | ||
data: NonNull<T>, | ||
arena: Arena, | ||
} | ||
|
||
impl<T: ?Sized + 'static> OwnedArenaBox<T> { | ||
/// Construct `OwnedArenaBox` from raw pointers and its owning arena. | ||
/// | ||
/// # Safety | ||
/// - `data` must satisfy the safety constraints of pointer::as_mut::<'a>() | ||
/// where 'a is the passed arena's lifetime (`data` should be valid and | ||
/// not mutated while this struct is live). | ||
/// - `data` should be a pointer into a block from a previous allocation on | ||
/// `arena`, or to another arena fused to it, or should be pointing at | ||
/// 'static data (and if it is pointing at any struct like upb_Message, | ||
/// all data transitively reachable should similarly be kept live by | ||
/// `arena` or be 'static). | ||
pub unsafe fn new(data: NonNull<T>, arena: Arena) -> Self { | ||
OwnedArenaBox { arena, data } | ||
} | ||
|
||
pub fn data(&self) -> *const T { | ||
self.data.as_ptr() | ||
} | ||
|
||
pub fn into_parts(self) -> (NonNull<T>, Arena) { | ||
(self.data, self.arena) | ||
} | ||
} | ||
|
||
impl<T: ?Sized + 'static> Deref for OwnedArenaBox<T> { | ||
type Target = T; | ||
fn deref(&self) -> &Self::Target { | ||
self.as_ref() | ||
} | ||
} | ||
|
||
impl<T: ?Sized + 'static> DerefMut for OwnedArenaBox<T> { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
self.as_mut() | ||
} | ||
} | ||
|
||
impl<T: ?Sized + 'static> AsRef<T> for OwnedArenaBox<T> { | ||
fn as_ref(&self) -> &T { | ||
// SAFETY: | ||
// - `data` is valid under the conditions set on ::new(). | ||
unsafe { self.data.as_ref() } | ||
} | ||
} | ||
|
||
impl<T: ?Sized + 'static> AsMut<T> for OwnedArenaBox<T> { | ||
fn as_mut(&mut self) -> &mut T { | ||
// SAFETY: | ||
// - `data` is valid under the conditions set on ::new(). | ||
unsafe { self.data.as_mut() } | ||
} | ||
} | ||
|
||
impl<T: Debug + 'static> Debug for OwnedArenaBox<T> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_tuple("OwnedArenaBox").field(self.deref()).finish() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use std::str; | ||
|
||
#[test] | ||
fn test_byte_slice_pointer_roundtrip() { | ||
let arena = Arena::new(); | ||
let original_data: &'static [u8] = b"Hello world"; | ||
let owned_data = unsafe { OwnedArenaBox::new(original_data.into(), arena) }; | ||
assert_eq!(&*owned_data, b"Hello world"); | ||
} | ||
|
||
#[test] | ||
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 owned_data = unsafe { OwnedArenaBox::new(arena_alloc_str, arena) }; | ||
assert_eq!(&*owned_data, s); | ||
} | ||
|
||
#[test] | ||
fn test_sized_type_roundtrip() { | ||
let arena = Arena::new(); | ||
let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).into(); | ||
let mut owned_data = unsafe { OwnedArenaBox::new(arena_alloc_u32, arena) }; | ||
assert_eq!(*owned_data, 7); | ||
*owned_data = 8; | ||
assert_eq!(*owned_data, 8); | ||
} | ||
} |
Oops, something went wrong.