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