bump_scope/chunk/header.rs
1use core::{cell::Cell, ptr::NonNull};
2
3use crate::{polyfill::non_null, settings::BumpAllocatorSettings};
4
5/// The chunk header that lives at
6/// - the start of the allocation when upwards bumping
7/// - the end of the allocation when downwards bumping
8///
9/// All non-`Cell` fields are immutable.
10#[repr(C, align(16))]
11pub(crate) struct ChunkHeader<A = ()> {
12 pub(crate) pos: Cell<NonNull<u8>>,
13 pub(crate) end: NonNull<u8>,
14
15 pub(crate) prev: Cell<Option<NonNull<Self>>>,
16 pub(crate) next: Cell<Option<NonNull<Self>>>,
17
18 pub(crate) allocator: A,
19}
20
21/// Wraps a [`ChunkHeader`], making it Sync so it can be used as a static.
22/// The dummy chunk is never mutated, so this is fine.
23struct DummyChunkHeader(ChunkHeader);
24
25unsafe impl Sync for DummyChunkHeader {}
26
27/// We create a dummy chunks with a negative capacity, so all allocations will fail.
28///
29/// The pointers used for `pos` and `end` are chosen to be pointers into the same static dummy chunk.
30///
31/// It's irrelevant where the pointers point to, they just need to:
32/// - be aligned to [`MIN_CHUNK_ALIGN`]
33/// - denote a negative capacity (currently guaranteed to be -16)
34/// - point to some existing object, not a dangling pointer since a dangling pointer could
35/// theoretically be a valid pointer to some other chunk
36macro_rules! dummy_chunk {
37 ($name:ident) => {
38 pub(crate) const fn $name<S: BumpAllocatorSettings>() -> NonNull<ChunkHeader> {
39 static UP_CHUNK: DummyChunkHeader = DummyChunkHeader(ChunkHeader {
40 // SAFETY: Due to `align(16)`, `ChunkHeader`'s size is `>= 16`, so a `byte_add` of 16 is in bounds.
41 // We could also use `.add(1)` here, but we currently guarantee a capacity of -16
42 pos: Cell::new(unsafe { UP_CHUNK_PTR.cast().byte_add(16) }),
43 end: UP_CHUNK_PTR.cast(),
44 prev: Cell::new(None),
45 next: Cell::new(None),
46 allocator: (),
47 });
48
49 static DOWN_CHUNK: DummyChunkHeader = DummyChunkHeader(ChunkHeader {
50 pos: Cell::new(DOWN_CHUNK_PTR.cast()),
51 // SAFETY: Due to `align(16)`, `ChunkHeader`'s size is `>= 16`, so a `byte_add` of 16 is in bounds.
52 // We could also use `.add(1)` here, but we currently guarantee a capacity of -16
53 end: unsafe { DOWN_CHUNK_PTR.cast().byte_add(16) },
54 prev: Cell::new(None),
55 next: Cell::new(None),
56 allocator: (),
57 });
58
59 const UP_CHUNK_PTR: NonNull<ChunkHeader> = non_null::from_ref(&UP_CHUNK.0);
60 const DOWN_CHUNK_PTR: NonNull<ChunkHeader> = non_null::from_ref(&DOWN_CHUNK.0);
61
62 if S::UP { UP_CHUNK_PTR } else { DOWN_CHUNK_PTR }
63 }
64 };
65}
66
67impl ChunkHeader {
68 dummy_chunk!(unallocated);
69 dummy_chunk!(claimed);
70}