• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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