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, A, S = BumpSettings>
33where
34 S: BumpAllocatorSettings,
35{
36 chunk: RawChunk<A, S>,
37 marker: PhantomData<&'a ()>,
38}
39
40impl<A, S> Clone for Stats<'_, A, S>
41where
42 S: BumpAllocatorSettings,
43{
44 fn clone(&self) -> Self {
45 *self
46 }
47}
48
49impl<A, S> Copy for Stats<'_, A, S> where S: BumpAllocatorSettings {}
50
51impl<A, S> PartialEq for Stats<'_, A, S>
52where
53 S: BumpAllocatorSettings,
54{
55 fn eq(&self, other: &Self) -> bool {
56 self.chunk.header() == other.chunk.header()
57 }
58}
59
60impl<A, S> Eq for Stats<'_, A, S> where S: BumpAllocatorSettings {}
61
62impl<A, S> Debug for Stats<'_, A, 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, A, S> Stats<'a, A, S>
72where
73 S: BumpAllocatorSettings,
74{
75 #[inline]
76 pub(crate) fn from_raw_chunk(chunk: RawChunk<A, 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, 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, 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, A, S>> {
174 Some(Chunk {
175 chunk: self.chunk.as_non_dummy()?,
176 marker: self.marker,
177 })
178 }
179
180 #[inline]
182 #[must_use]
183 pub fn allocator(self) -> Option<&'a A> {
184 Some(self.current_chunk()?.allocator())
185 }
186}
187
188impl<'a, A, S> From<Chunk<'a, A, S>> for Stats<'a, A, S>
189where
190 S: BumpAllocatorSettings,
191{
192 fn from(chunk: Chunk<'a, A, S>) -> Self {
193 Stats {
194 chunk: *chunk.chunk,
195 marker: PhantomData,
196 }
197 }
198}
199
200impl<A, S> Default for Stats<'_, A, S>
201where
202 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
203{
204 fn default() -> Self {
205 Self {
206 chunk: RawChunk::UNALLOCATED,
207 marker: PhantomData,
208 }
209 }
210}
211
212#[repr(transparent)]
216pub struct Chunk<'a, A, S>
217where
218 S: BumpAllocatorSettings,
219{
220 pub(crate) chunk: NonDummyChunk<A, S>,
221 marker: PhantomData<&'a ()>,
222}
223
224impl<A, S> Clone for Chunk<'_, A, S>
225where
226 S: BumpAllocatorSettings,
227{
228 fn clone(&self) -> Self {
229 *self
230 }
231}
232
233impl<A, S> Copy for Chunk<'_, A, S> where S: BumpAllocatorSettings {}
234
235impl<A, S> PartialEq for Chunk<'_, A, S>
236where
237 S: BumpAllocatorSettings,
238{
239 fn eq(&self, other: &Self) -> bool {
240 self.chunk.header() == other.chunk.header()
241 }
242}
243
244impl<A, S> Eq for Chunk<'_, A, S> where S: BumpAllocatorSettings {}
245
246impl<A, S> Debug for Chunk<'_, A, S>
247where
248 S: BumpAllocatorSettings,
249{
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 f.debug_struct("Chunk")
252 .field("allocated", &self.allocated())
253 .field("capacity", &self.capacity())
254 .finish()
255 }
256}
257
258impl<'a, A, S> Chunk<'a, A, S>
259where
260 S: BumpAllocatorSettings,
261{
262 #[cfg(debug_assertions)]
263 pub(crate) fn header(self) -> NonNull<ChunkHeader<A>> {
264 self.chunk.header()
265 }
266
267 #[must_use]
269 #[inline(always)]
270 pub fn prev(self) -> Option<Self> {
271 Some(Chunk {
272 chunk: self.chunk.prev()?,
273 marker: PhantomData,
274 })
275 }
276
277 #[must_use]
279 #[inline(always)]
280 pub fn next(self) -> Option<Self> {
281 Some(Chunk {
282 chunk: self.chunk.next()?,
283 marker: PhantomData,
284 })
285 }
286
287 #[must_use]
289 #[inline(always)]
290 pub fn iter_prev(self) -> ChunkPrevIter<'a, A, S> {
291 ChunkPrevIter { chunk: self.prev() }
292 }
293
294 #[must_use]
296 #[inline(always)]
297 pub fn iter_next(self) -> ChunkNextIter<'a, A, S> {
298 ChunkNextIter { chunk: self.next() }
299 }
300
301 #[must_use]
303 #[inline]
304 pub fn size(self) -> usize {
305 self.chunk.size().get()
306 }
307
308 #[inline]
310 #[must_use]
311 pub fn capacity(self) -> usize {
312 self.chunk.capacity()
313 }
314
315 #[inline]
322 #[must_use]
323 pub fn allocated(self) -> usize {
324 self.chunk.allocated()
325 }
326
327 #[inline]
333 #[must_use]
334 pub fn remaining(self) -> usize {
335 self.chunk.remaining()
336 }
337
338 #[inline]
340 #[must_use]
341 pub fn chunk_start(self) -> NonNull<u8> {
342 self.chunk.chunk_start()
343 }
344
345 #[inline]
347 #[must_use]
348 pub fn chunk_end(self) -> NonNull<u8> {
349 self.chunk.chunk_end()
350 }
351
352 #[inline]
354 #[must_use]
355 pub fn content_start(self) -> NonNull<u8> {
356 self.chunk.content_start()
357 }
358
359 #[inline]
361 #[must_use]
362 pub fn content_end(self) -> NonNull<u8> {
363 self.chunk.content_end()
364 }
365
366 #[inline]
371 #[must_use]
372 pub fn bump_position(self) -> NonNull<u8> {
373 self.chunk.pos()
374 }
375
376 #[inline]
378 #[must_use]
379 pub fn allocator(self) -> &'a A {
380 self.chunk.allocator()
381 }
382}
383
384pub struct ChunkPrevIter<'a, A, S>
386where
387 S: BumpAllocatorSettings,
388{
389 #[expect(missing_docs)]
390 pub chunk: Option<Chunk<'a, A, S>>,
391}
392
393impl<A, S> Clone for ChunkPrevIter<'_, A, S>
394where
395 S: BumpAllocatorSettings,
396{
397 fn clone(&self) -> Self {
398 *self
399 }
400}
401
402impl<A, S> Copy for ChunkPrevIter<'_, A, S> where S: BumpAllocatorSettings {}
403
404impl<A, S> PartialEq for ChunkPrevIter<'_, A, S>
405where
406 S: BumpAllocatorSettings,
407{
408 fn eq(&self, other: &Self) -> bool {
409 self.chunk == other.chunk
410 }
411}
412
413impl<A, S> Eq for ChunkPrevIter<'_, A, S> where S: BumpAllocatorSettings {}
414
415impl<A, S> Default for ChunkPrevIter<'_, A, S>
416where
417 S: BumpAllocatorSettings,
418{
419 fn default() -> Self {
420 Self { chunk: None }
421 }
422}
423
424impl<'a, A, S> Iterator for ChunkPrevIter<'a, A, S>
425where
426 S: BumpAllocatorSettings,
427{
428 type Item = Chunk<'a, A, S>;
429
430 #[inline(always)]
431 fn next(&mut self) -> Option<Self::Item> {
432 let chunk = self.chunk?;
433 self.chunk = chunk.prev();
434 Some(chunk)
435 }
436}
437
438impl<A, S> FusedIterator for ChunkPrevIter<'_, A, S> where S: BumpAllocatorSettings {}
439
440impl<A, S> Debug for ChunkPrevIter<'_, A, S>
441where
442 S: BumpAllocatorSettings,
443{
444 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
445 f.debug_list().entries(*self).finish()
446 }
447}
448
449pub struct ChunkNextIter<'a, A, S>
451where
452 S: BumpAllocatorSettings,
453{
454 #[expect(missing_docs)]
455 pub chunk: Option<Chunk<'a, A, S>>,
456}
457
458impl<A, S> Clone for ChunkNextIter<'_, A, S>
459where
460 S: BumpAllocatorSettings,
461{
462 fn clone(&self) -> Self {
463 *self
464 }
465}
466
467impl<A, S> Copy for ChunkNextIter<'_, A, S> where S: BumpAllocatorSettings {}
468
469impl<A, S> PartialEq for ChunkNextIter<'_, A, S>
470where
471 S: BumpAllocatorSettings,
472{
473 fn eq(&self, other: &Self) -> bool {
474 self.chunk == other.chunk
475 }
476}
477
478impl<A, S> Eq for ChunkNextIter<'_, A, S> where S: BumpAllocatorSettings {}
479
480impl<A, S> Default for ChunkNextIter<'_, A, S>
481where
482 S: BumpAllocatorSettings,
483{
484 fn default() -> Self {
485 Self { chunk: None }
486 }
487}
488
489impl<'a, A, S> Iterator for ChunkNextIter<'a, A, S>
490where
491 S: BumpAllocatorSettings,
492{
493 type Item = Chunk<'a, A, S>;
494
495 #[inline(always)]
496 fn next(&mut self) -> Option<Self::Item> {
497 let chunk = self.chunk?;
498 self.chunk = chunk.next();
499 Some(chunk)
500 }
501}
502
503impl<A, S> FusedIterator for ChunkNextIter<'_, A, S> where S: BumpAllocatorSettings {}
504
505impl<A, S> Debug for ChunkNextIter<'_, A, S>
506where
507 S: BumpAllocatorSettings,
508{
509 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
510 f.debug_list().entries(self.map(Chunk::size)).finish()
511 }
512}