1use core::{
11 fmt::{self, Debug},
12 iter::FusedIterator,
13 marker::PhantomData,
14 ptr::NonNull,
15};
16
17use crate::{
18 raw_bump::{NonDummyChunk, RawChunk},
19 settings::{BumpAllocatorSettings, BumpSettings, False},
20};
21
22#[cfg(debug_assertions)]
23use crate::chunk::ChunkHeader;
24
25mod any;
26
27pub use any::{AnyChunk, AnyChunkNextIter, AnyChunkPrevIter, AnyStats};
28
29pub struct Stats<'a, S = BumpSettings>
33where
34 S: BumpAllocatorSettings,
35{
36 chunk: RawChunk<S>,
37 marker: PhantomData<&'a ()>,
38}
39
40impl<S> Clone for Stats<'_, S>
41where
42 S: BumpAllocatorSettings,
43{
44 fn clone(&self) -> Self {
45 *self
46 }
47}
48
49impl<S> Copy for Stats<'_, S> where S: BumpAllocatorSettings {}
50
51impl<S> PartialEq for Stats<'_, S>
52where
53 S: BumpAllocatorSettings,
54{
55 fn eq(&self, other: &Self) -> bool {
56 self.chunk.header() == other.chunk.header()
57 }
58}
59
60impl<S> Eq for Stats<'_, S> where S: BumpAllocatorSettings {}
61
62impl<S> Debug for Stats<'_, S>
63where
64 S: BumpAllocatorSettings,
65{
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 AnyStats::from(*self).debug_format("Stats", f)
68 }
69}
70
71impl<'a, S> Stats<'a, S>
72where
73 S: BumpAllocatorSettings,
74{
75 #[inline]
76 pub(crate) fn from_raw_chunk(chunk: RawChunk<S>) -> Self {
77 Self {
78 chunk,
79 marker: PhantomData,
80 }
81 }
82
83 #[must_use]
85 pub fn count(self) -> usize {
86 let Some(current) = self.current_chunk() else { return 0 };
87
88 let mut sum = 1;
89 current.iter_prev().for_each(|_| sum += 1);
90 current.iter_next().for_each(|_| sum += 1);
91 sum
92 }
93
94 #[must_use]
96 pub fn size(self) -> usize {
97 let Some(current) = self.current_chunk() else { return 0 };
98
99 let mut sum = current.size();
100 current.iter_prev().for_each(|chunk| sum += chunk.size());
101 current.iter_next().for_each(|chunk| sum += chunk.size());
102 sum
103 }
104
105 #[must_use]
107 pub fn capacity(self) -> usize {
108 let Some(current) = self.current_chunk() else { return 0 };
109
110 let mut sum = current.capacity();
111 current.iter_prev().for_each(|chunk| sum += chunk.capacity());
112 current.iter_next().for_each(|chunk| sum += chunk.capacity());
113 sum
114 }
115
116 #[must_use]
122 pub fn allocated(self) -> usize {
123 let Some(current) = self.current_chunk() else { return 0 };
124
125 let mut sum = current.allocated();
126 current.iter_prev().for_each(|chunk| sum += chunk.capacity());
127 sum
128 }
129
130 #[must_use]
135 pub fn remaining(self) -> usize {
136 let Some(current) = self.current_chunk() else { return 0 };
137
138 let mut sum = current.remaining();
139 current.iter_next().for_each(|chunk| sum += chunk.capacity());
140 sum
141 }
142
143 #[must_use]
145 pub fn small_to_big(self) -> ChunkNextIter<'a, S> {
146 let Some(mut start) = self.current_chunk() else {
147 return ChunkNextIter { chunk: None };
148 };
149
150 while let Some(chunk) = start.prev() {
151 start = chunk;
152 }
153
154 ChunkNextIter { chunk: Some(start) }
155 }
156
157 #[must_use]
159 pub fn big_to_small(self) -> ChunkPrevIter<'a, S> {
160 let Some(mut start) = self.current_chunk() else {
161 return ChunkPrevIter { chunk: None };
162 };
163
164 while let Some(chunk) = start.next() {
165 start = chunk;
166 }
167
168 ChunkPrevIter { chunk: Some(start) }
169 }
170
171 #[must_use]
173 pub fn current_chunk(self) -> Option<Chunk<'a, S>> {
174 Some(Chunk {
175 chunk: self.chunk.as_non_dummy()?,
176 marker: self.marker,
177 })
178 }
179}
180
181impl<'a, S> From<Chunk<'a, S>> for Stats<'a, S>
182where
183 S: BumpAllocatorSettings,
184{
185 fn from(chunk: Chunk<'a, S>) -> Self {
186 Stats {
187 chunk: *chunk.chunk,
188 marker: PhantomData,
189 }
190 }
191}
192
193impl<S> Default for Stats<'_, S>
194where
195 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
196{
197 fn default() -> Self {
198 Self {
199 chunk: RawChunk::UNALLOCATED,
200 marker: PhantomData,
201 }
202 }
203}
204
205#[repr(transparent)]
209pub struct Chunk<'a, S>
210where
211 S: BumpAllocatorSettings,
212{
213 pub(crate) chunk: NonDummyChunk<S>,
214 marker: PhantomData<&'a ()>,
215}
216
217impl<S> Clone for Chunk<'_, S>
218where
219 S: BumpAllocatorSettings,
220{
221 fn clone(&self) -> Self {
222 *self
223 }
224}
225
226impl<S> Copy for Chunk<'_, S> where S: BumpAllocatorSettings {}
227
228impl<S> PartialEq for Chunk<'_, S>
229where
230 S: BumpAllocatorSettings,
231{
232 fn eq(&self, other: &Self) -> bool {
233 self.chunk.header() == other.chunk.header()
234 }
235}
236
237impl<S> Eq for Chunk<'_, S> where S: BumpAllocatorSettings {}
238
239impl<S> Debug for Chunk<'_, S>
240where
241 S: BumpAllocatorSettings,
242{
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f.debug_struct("Chunk")
245 .field("allocated", &self.allocated())
246 .field("capacity", &self.capacity())
247 .finish()
248 }
249}
250
251impl<'a, S> Chunk<'a, S>
252where
253 S: BumpAllocatorSettings,
254{
255 #[cfg(debug_assertions)]
256 pub(crate) fn header(self) -> NonNull<ChunkHeader> {
257 self.chunk.header().cast()
258 }
259
260 #[must_use]
262 #[inline(always)]
263 pub fn prev(self) -> Option<Self> {
264 Some(Chunk {
265 chunk: self.chunk.prev()?,
266 marker: PhantomData,
267 })
268 }
269
270 #[must_use]
272 #[inline(always)]
273 pub fn next(self) -> Option<Self> {
274 Some(Chunk {
275 chunk: self.chunk.next()?,
276 marker: PhantomData,
277 })
278 }
279
280 #[must_use]
282 #[inline(always)]
283 pub fn iter_prev(self) -> ChunkPrevIter<'a, S> {
284 ChunkPrevIter { chunk: self.prev() }
285 }
286
287 #[must_use]
289 #[inline(always)]
290 pub fn iter_next(self) -> ChunkNextIter<'a, S> {
291 ChunkNextIter { chunk: self.next() }
292 }
293
294 #[must_use]
296 #[inline]
297 pub fn size(self) -> usize {
298 self.chunk.size().get()
299 }
300
301 #[must_use]
303 #[inline]
304 pub fn capacity(self) -> usize {
305 self.chunk.capacity()
306 }
307
308 #[must_use]
315 #[inline]
316 pub fn allocated(self) -> usize {
317 self.chunk.allocated()
318 }
319
320 #[must_use]
326 #[inline]
327 pub fn remaining(self) -> usize {
328 self.chunk.remaining()
329 }
330
331 #[must_use]
333 #[inline]
334 pub fn chunk_start(self) -> NonNull<u8> {
335 self.chunk.chunk_start()
336 }
337
338 #[must_use]
340 #[inline]
341 pub fn chunk_end(self) -> NonNull<u8> {
342 self.chunk.chunk_end()
343 }
344
345 #[must_use]
347 #[inline]
348 pub fn content_start(self) -> NonNull<u8> {
349 self.chunk.content_start()
350 }
351
352 #[must_use]
354 #[inline]
355 pub fn content_end(self) -> NonNull<u8> {
356 self.chunk.content_end()
357 }
358
359 #[must_use]
364 #[inline]
365 pub fn bump_position(self) -> NonNull<u8> {
366 self.chunk.pos()
367 }
368}
369
370pub struct ChunkPrevIter<'a, S>
372where
373 S: BumpAllocatorSettings,
374{
375 #[expect(missing_docs)]
376 pub chunk: Option<Chunk<'a, S>>,
377}
378
379impl<S> Clone for ChunkPrevIter<'_, S>
380where
381 S: BumpAllocatorSettings,
382{
383 fn clone(&self) -> Self {
384 *self
385 }
386}
387
388impl<S> Copy for ChunkPrevIter<'_, S> where S: BumpAllocatorSettings {}
389
390impl<S> PartialEq for ChunkPrevIter<'_, S>
391where
392 S: BumpAllocatorSettings,
393{
394 fn eq(&self, other: &Self) -> bool {
395 self.chunk == other.chunk
396 }
397}
398
399impl<S> Eq for ChunkPrevIter<'_, S> where S: BumpAllocatorSettings {}
400
401impl<S> Default for ChunkPrevIter<'_, S>
402where
403 S: BumpAllocatorSettings,
404{
405 fn default() -> Self {
406 Self { chunk: None }
407 }
408}
409
410impl<'a, S> Iterator for ChunkPrevIter<'a, S>
411where
412 S: BumpAllocatorSettings,
413{
414 type Item = Chunk<'a, S>;
415
416 #[inline(always)]
417 fn next(&mut self) -> Option<Self::Item> {
418 let chunk = self.chunk?;
419 self.chunk = chunk.prev();
420 Some(chunk)
421 }
422}
423
424impl<S> FusedIterator for ChunkPrevIter<'_, S> where S: BumpAllocatorSettings {}
425
426impl<S> Debug for ChunkPrevIter<'_, S>
427where
428 S: BumpAllocatorSettings,
429{
430 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
431 f.debug_list().entries(*self).finish()
432 }
433}
434
435pub struct ChunkNextIter<'a, S>
437where
438 S: BumpAllocatorSettings,
439{
440 #[expect(missing_docs)]
441 pub chunk: Option<Chunk<'a, S>>,
442}
443
444impl<S> Clone for ChunkNextIter<'_, S>
445where
446 S: BumpAllocatorSettings,
447{
448 fn clone(&self) -> Self {
449 *self
450 }
451}
452
453impl<S> Copy for ChunkNextIter<'_, S> where S: BumpAllocatorSettings {}
454
455impl<S> PartialEq for ChunkNextIter<'_, S>
456where
457 S: BumpAllocatorSettings,
458{
459 fn eq(&self, other: &Self) -> bool {
460 self.chunk == other.chunk
461 }
462}
463
464impl<S> Eq for ChunkNextIter<'_, S> where S: BumpAllocatorSettings {}
465
466impl<S> Default for ChunkNextIter<'_, S>
467where
468 S: BumpAllocatorSettings,
469{
470 fn default() -> Self {
471 Self { chunk: None }
472 }
473}
474
475impl<'a, S> Iterator for ChunkNextIter<'a, S>
476where
477 S: BumpAllocatorSettings,
478{
479 type Item = Chunk<'a, S>;
480
481 #[inline(always)]
482 fn next(&mut self) -> Option<Self::Item> {
483 let chunk = self.chunk?;
484 self.chunk = chunk.next();
485 Some(chunk)
486 }
487}
488
489impl<S> FusedIterator for ChunkNextIter<'_, S> where S: BumpAllocatorSettings {}
490
491impl<S> Debug for ChunkNextIter<'_, S>
492where
493 S: BumpAllocatorSettings,
494{
495 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
496 f.debug_list().entries(self.map(Chunk::size)).finish()
497 }
498}