1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2024 Google LLC. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 use super::Arena; 9 use core::fmt::{self, Debug}; 10 use core::ops::{Deref, DerefMut}; 11 use core::ptr::NonNull; 12 13 /// An 'owned' T, similar to a Box<T> where the T is data 14 /// held in a upb Arena. By holding the data pointer and a corresponding arena 15 /// together the data liveness is be maintained. 16 /// 17 /// This struct is conceptually self-referential, where `data` points at memory 18 /// inside `arena`. This avoids typical concerns of self-referential data 19 /// structures because `arena` modifications (other than drop) will never 20 /// invalidate `data`, and `data` and `arena` are both behind indirections which 21 /// avoids any concern with core::mem::swap. 22 pub struct OwnedArenaBox<T: ?Sized + 'static> { 23 data: NonNull<T>, 24 arena: Arena, 25 } 26 27 impl<T: ?Sized + 'static> OwnedArenaBox<T> { 28 /// Construct `OwnedArenaBox` from raw pointers and its owning arena. 29 /// 30 /// # Safety 31 /// - `data` must satisfy the safety constraints of pointer::as_mut::<'a>() 32 /// where 'a is the passed arena's lifetime (`data` should be valid and 33 /// not mutated while this struct is live). 34 /// - `data` should be a pointer into a block from a previous allocation on 35 /// `arena`, or to another arena fused to it, or should be pointing at 36 /// 'static data (and if it is pointing at any struct like upb_Message, 37 /// all data transitively reachable should similarly be kept live by 38 /// `arena` or be 'static). new(data: NonNull<T>, arena: Arena) -> Self39 pub unsafe fn new(data: NonNull<T>, arena: Arena) -> Self { 40 OwnedArenaBox { arena, data } 41 } 42 data(&self) -> *const T43 pub fn data(&self) -> *const T { 44 self.data.as_ptr() 45 } 46 into_parts(self) -> (NonNull<T>, Arena)47 pub fn into_parts(self) -> (NonNull<T>, Arena) { 48 (self.data, self.arena) 49 } 50 } 51 52 impl<T: ?Sized + 'static> Deref for OwnedArenaBox<T> { 53 type Target = T; deref(&self) -> &Self::Target54 fn deref(&self) -> &Self::Target { 55 self.as_ref() 56 } 57 } 58 59 impl<T: ?Sized + 'static> DerefMut for OwnedArenaBox<T> { deref_mut(&mut self) -> &mut Self::Target60 fn deref_mut(&mut self) -> &mut Self::Target { 61 self.as_mut() 62 } 63 } 64 65 impl<T: ?Sized + 'static> AsRef<T> for OwnedArenaBox<T> { as_ref(&self) -> &T66 fn as_ref(&self) -> &T { 67 // SAFETY: 68 // - `data` is valid under the conditions set on ::new(). 69 unsafe { self.data.as_ref() } 70 } 71 } 72 73 impl<T: ?Sized + 'static> AsMut<T> for OwnedArenaBox<T> { as_mut(&mut self) -> &mut T74 fn as_mut(&mut self) -> &mut T { 75 // SAFETY: 76 // - `data` is valid under the conditions set on ::new(). 77 unsafe { self.data.as_mut() } 78 } 79 } 80 81 impl<T: Debug + 'static> Debug for OwnedArenaBox<T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 83 f.debug_tuple("OwnedArenaBox").field(self.deref()).finish() 84 } 85 } 86 87 #[cfg(test)] 88 mod tests { 89 use super::*; 90 use core::str; 91 use googletest::gtest; 92 93 #[gtest] test_byte_slice_pointer_roundtrip()94 fn test_byte_slice_pointer_roundtrip() { 95 let arena = Arena::new(); 96 let original_data: &'static [u8] = b"Hello world"; 97 let owned_data = unsafe { OwnedArenaBox::new(original_data.into(), arena) }; 98 assert_eq!(&*owned_data, b"Hello world"); 99 } 100 101 #[gtest] test_alloc_str_roundtrip()102 fn test_alloc_str_roundtrip() { 103 let arena = Arena::new(); 104 let s: &str = "Hello"; 105 let arena_alloc_str: NonNull<str> = arena.copy_str_in(s).unwrap().into(); 106 let owned_data = unsafe { OwnedArenaBox::new(arena_alloc_str, arena) }; 107 assert_eq!(&*owned_data, s); 108 } 109 110 #[gtest] test_sized_type_roundtrip()111 fn test_sized_type_roundtrip() { 112 let arena = Arena::new(); 113 let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).unwrap().into(); 114 let mut owned_data = unsafe { OwnedArenaBox::new(arena_alloc_u32, arena) }; 115 assert_eq!(*owned_data, 7); 116 *owned_data = 8; 117 assert_eq!(*owned_data, 8); 118 } 119 } 120