1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use ;
use Error;
/// An error indicating that an allocation failed for any reason, including
/// memory exhaustion or because the requested layout didn't meet the
/// allocator's alignment requirements.
;
/// A trait for global allocators within a game that are able to deallocate any
/// memory on the game's main heap. Generally corresponds to the drop logic for
/// `DLUT::DLAutoDeletePtr` in games from _Bloodborne_ forward.
///
/// The API for this generally matches [`std::alloc::Allocator`] where possible.
/// However, it diverges in certain places that are necessary for compatibility
/// with the games' memory management.
///
/// ### Allocator compatibility
///
/// An allocator is *compatible with* this allocator if memory it allocates can
/// be passed to [`deallocate`] without causing undefined behavior. A given
/// [`GameAllocator]` must be compatible with itself, but other allocators may
/// also be compatible. For example, the `GameAllocator` may track global
/// allocation arenas and determine which global allocator to use to deallocate
/// a given pointer based on where it appears in those arenas.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block is *currently allocated* by
/// an allocator. This means that:
///
/// * the starting address for that memory block was previously returned by
/// [`allocate`] *or* by another allocator that's known to be [*compatible
/// with*] this one, and
/// * the memory block has not subsequently been deallocated.
///
/// A memory block is deallocated by a call to [`deallocate`].
///
/// [`allocate`]: Self::allocate
/// [*compatible with*]: #allocator-compatibility
/// [`deallocate`]: Self::deallocate
///
/// ### Memory fitting
///
/// Some of the methods require that a `layout` *fit* a memory block or vice
/// versa. This means that the following conditions must hold:
///
/// * the memory block must be *currently allocated* with alignment of
/// [`layout.align()`], and
///
/// * [`layout.size()`] must fall in the range `min ..= max`, where:
/// - `min` is the size of the layout used to allocate the block, and
/// - `max` is the actual size returned from [`allocate`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
/// A [`GameAllocator`] that never actually allocates or drops memory.
///
/// [`allocate`] always returns [`AllocError`] and [`deallocate`] always panics.
///
/// [`allocate`]: Self::allocate
/// [`deallocate`]: Self::deallocate
///
/// This is intended to by used as the allocator for types such as [`OwnedPtr`]
/// that represent memory allocated by the game that *don't* use the game's main
/// heap and so whose deallocation behavior is unknown. It's always incorrect to
/// try to create or destroy such types in Rust code.
///
/// [`OwnedPtr`]: crate::OwnedPtr
///
/// Because [`NoOpAllocator::deallocate`] never has undefined behavior for any
/// memory blocks, all allocators are technically *compatible with* it.
;