1use core::{alloc::Layout, marker::PhantomData, num::NonZeroUsize};
2
3use crate::{
4 chunk::{ChunkHeader, ChunkSizeConfig, MIN_CHUNK_ALIGN},
5 settings::Boolean,
6};
7
8const _: () = assert!(MIN_CHUNK_ALIGN == crate::bumping::MIN_CHUNK_ALIGN);
9
10pub(crate) type AssumedMallocOverhead = [usize; 2];
12
13pub const fn config<A, Up>() -> ChunkSizeConfig
14where
15 Up: Boolean,
16{
17 ChunkSizeConfig {
18 up: Up::VALUE,
19 assumed_malloc_overhead_layout: Layout::new::<AssumedMallocOverhead>(),
20 chunk_header_layout: Layout::new::<ChunkHeader<A>>(),
21 }
22}
23
24macro_rules! attempt {
25 ($expr:expr) => {
26 match $expr {
27 Some(some) => some,
28 None => return None,
29 }
30 };
31}
32
33pub struct ChunkSize<A, Up> {
34 size: NonZeroUsize,
35 marker: PhantomData<fn() -> (A, Up)>,
36}
37
38impl<A, Up> Clone for ChunkSize<A, Up> {
39 fn clone(&self) -> Self {
40 *self
41 }
42}
43
44impl<A, Up> Copy for ChunkSize<A, Up> {}
45
46impl<A, Up> ChunkSize<A, Up>
47where
48 Up: Boolean,
49{
50 pub const ZERO: Self = match Self::from_hint(0) {
51 Some(some) => some,
52 None => panic!("failed to calculate zero chunk size"),
53 };
54
55 pub const fn from_hint(size_hint: usize) -> Option<Self> {
56 ChunkSizeHint::new(size_hint).calc_size()
57 }
58
59 pub const fn from_capacity(layout: Layout) -> Option<Self> {
60 attempt!(ChunkSizeHint::for_capacity(layout)).calc_size()
61 }
62
63 pub const fn align_allocation_size(self, size: usize) -> usize {
65 _ = self;
66 config::<A, Up>().align_size(size)
67 }
68
69 pub const fn layout(self) -> Option<Layout> {
70 let size = self.size.get();
71 let align = core::mem::align_of::<ChunkHeader<A>>();
72 match Layout::from_size_align(size, align) {
73 Ok(ok) => Some(ok),
74 Err(_) => None,
75 }
76 }
77
78 pub const fn max(self, other: Self) -> Self {
79 if self.size.get() > other.size.get() { self } else { other }
80 }
81}
82pub struct ChunkSizeHint<A, Up>(usize, PhantomData<fn() -> (A, Up)>);
83
84impl<A, Up> Clone for ChunkSizeHint<A, Up> {
85 fn clone(&self) -> Self {
86 *self
87 }
88}
89
90impl<A, Up> Copy for ChunkSizeHint<A, Up> {}
91
92impl<A, Up> ChunkSizeHint<A, Up>
93where
94 Up: Boolean,
95{
96 pub const fn new(size_hint: usize) -> Self {
97 Self(size_hint, PhantomData)
98 }
99
100 pub const fn for_capacity(layout: Layout) -> Option<Self> {
101 Some(Self(attempt!(config::<A, Up>().calc_hint_from_capacity(layout)), PhantomData))
102 }
103
104 pub const fn calc_size(self) -> Option<ChunkSize<A, Up>> {
105 Some(ChunkSize {
106 size: attempt!(config::<A, Up>().calc_size_from_hint(self.0)),
107 marker: PhantomData,
108 })
109 }
110
111 pub const fn max(self, other: Self) -> Self {
112 if self.0 > other.0 { self } else { other }
113 }
114}