fromsoftware_shared/owned_pointer.rs
1use std::alloc::{Layout, handle_alloc_error};
2use std::ops::{Deref, DerefMut};
3use std::{fmt, marker::PhantomData, ptr::NonNull};
4
5use crate::{GameAllocator, NoOpAllocator};
6
7/// Pointer to a structure that the containing structure owns. You will generally use this to model
8/// structures in foreign memory when extending the game libraries. Do not use this in your own
9/// code as you're risking all rusts safety reasoning.
10///
11/// ## Safety
12///
13/// ### `OwnedPtr` in FFI
14///
15/// When declaring definitions of C++ structs and functions that use this type,
16/// the author must ensure several invariants hold true:
17///
18/// * This must be the only way to access the data it refers to without an
19/// `unsafe` block (not including the `unsafe` block necessary to call
20/// [`FromStatic::instance`]). This means there may not be any other structs
21/// or methods that provide an `OwnedPtr` or a reference to the underlying
22/// data.
23///
24/// Although *generally* this means that the struct that h olds an `OwnedPtr`
25/// is the same one that "owns" the data it refers to in the sense of being
26/// responsible for constructing and destroying it, that's not a hard
27/// requirement. In some cases, it may be more ergonomic to expose an
28/// `OwnedPtr` (or a reference) through a struct that's easy to obtain and use
29/// `NonNull` for the struct that actually has ownership.
30///
31/// * This must ensure that the backing memory is allocated by an allocator
32/// that's *compatible with* `A`. Note that all memory allocated in any way is
33/// *compatible with* [`NoOpAllocator`], so this requirement only matters if
34/// `A` is set explicitly.
35///
36/// [`FromStatic::instance`]: crate::FromStatic::instance
37///
38/// ### `OwnedPtr` and `Drop`
39///
40/// For any type `T` where Rust code might take ownership over an `OwnedPtr<T>`,
41/// the author should be sure that `T`'s [Drop] implementation is correct. (This
42/// is true in general for FFI types that Rust code can own.) There are two
43/// concerns here:
44///
45/// * Generally, C++ code will declare a specific destroy function for each
46/// type. In addition to calling the destructor method (`~T()`), this destroys
47/// any fields as well.
48///
49/// * Rust drops fields in declaration order but C++ destroys them in reverse
50/// declaration order.
51///
52/// To mitigate these issues, all fields with non-trivial drop/destructor
53/// implementations should by wrapped in [std::mem::ManuallyDrop]. If the C++
54/// code has a destroy method, it should be called from [Drop::drop]; otherwise,
55/// the implementation of [Drop::drop] should drop these fields in reverse
56/// declaration order.
57#[repr(transparent)]
58pub struct OwnedPtr<T, A: GameAllocator = NoOpAllocator> {
59 ptr: NonNull<T>,
60 _marker: PhantomData<A>,
61}
62
63impl<T, A: GameAllocator> OwnedPtr<T, A> {
64 /// Allocates memory with `A` and places `value` into it.
65 ///
66 /// This doesn’t actually allocate if `T` is zero-sized.
67 ///
68 /// **Important:** any type constructed this way should have an appropriate
69 /// [Drop::drop] implementation defined. [See above](#ownedptr-and-drop) for
70 /// details.
71 pub fn new(value: T) -> Self {
72 let layout = Layout::new::<T>();
73 if layout.size() == 0 {
74 OwnedPtr {
75 ptr: NonNull::dangling(),
76 _marker: Default::default(),
77 }
78 } else if let Ok(ptr) = A::allocate(layout) {
79 let ptr = ptr.cast::<T>();
80 unsafe { ptr.write(value) };
81 OwnedPtr {
82 ptr,
83 _marker: Default::default(),
84 }
85 } else {
86 handle_alloc_error(layout)
87 }
88 }
89
90 pub fn as_ptr(&self) -> *mut T {
91 self.ptr.as_ptr()
92 }
93}
94
95impl<T: Default, A: GameAllocator> Default for OwnedPtr<T, A> {
96 fn default() -> Self {
97 OwnedPtr::new(Default::default())
98 }
99}
100
101impl<T, A: GameAllocator> Deref for OwnedPtr<T, A> {
102 type Target = T;
103
104 fn deref(&self) -> &Self::Target {
105 unsafe { self.ptr.as_ref() }
106 }
107}
108
109impl<T, A: GameAllocator> AsRef<T> for OwnedPtr<T, A> {
110 fn as_ref(&self) -> &T {
111 self.deref()
112 }
113}
114
115impl<T, A: GameAllocator> DerefMut for OwnedPtr<T, A> {
116 fn deref_mut(&mut self) -> &mut Self::Target {
117 unsafe { self.ptr.as_mut() }
118 }
119}
120
121impl<T, A: GameAllocator> AsMut<T> for OwnedPtr<T, A> {
122 fn as_mut(&mut self) -> &mut T {
123 self.deref_mut()
124 }
125}
126
127impl<T, A: GameAllocator> fmt::Debug for OwnedPtr<T, A> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
129 self.ptr.fmt(f)
130 }
131}
132
133impl<T, A: GameAllocator> fmt::Pointer for OwnedPtr<T, A> {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
135 fmt::Pointer::fmt(&self.ptr, f)
136 }
137}
138
139impl<T, A: GameAllocator> Drop for OwnedPtr<T, A> {
140 fn drop(&mut self) {
141 unsafe {
142 self.ptr.drop_in_place();
143 if Layout::new::<T>().size() > 0 {
144 A::deallocate(self.ptr.cast::<u8>(), Layout::new::<T>());
145 }
146 }
147 }
148}
149
150unsafe impl<T: Send, A: GameAllocator + Send> Send for OwnedPtr<T, A> {}
151unsafe impl<T: Sync, A: GameAllocator + Sync> Sync for OwnedPtr<T, A> where T: Sync {}