1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! The error type returned by the fallible allocation path.
use fmt;
/// The reason a value could not be allocated into a [`Heap`](crate::Heap).
///
/// The heap addresses its slots with a 32-bit index, so it can hold up to
/// `u32::MAX + 1` distinct slots over its lifetime. Slots are reused as objects
/// are reclaimed, so this ceiling counts *simultaneously live plus never-yet-freed*
/// slots, not total allocations — a program that allocates and collects in a steady
/// loop never approaches it. Reaching the ceiling is the one recoverable failure an
/// allocation can hit; [`Heap::try_alloc`] reports it through this type instead of
/// aborting, so a runtime driving the heap from untrusted input can fail cleanly
/// rather than crash.
///
/// The enum is `#[non_exhaustive]`: a later phase may add a second failure mode
/// (for example, a per-heap byte budget), and a `match` on this type must already
/// account for it.
///
/// [`Heap::try_alloc`]: crate::Heap::try_alloc
///
/// # Examples
///
/// ```
/// use gc_lang::{GcError, Heap, Trace, Tracer};
///
/// struct Leaf;
/// impl Trace for Leaf {
/// fn trace(&self, _: &mut Tracer<'_>) {}
/// }
///
/// // The fallible path returns this type; the happy path yields a handle.
/// let mut heap: Heap<Leaf> = Heap::new();
/// let handle = heap.try_alloc(Leaf).expect("the first slot is always available");
/// assert!(heap.get(handle).is_some());
/// # let _ = GcError::CapacityExhausted;
/// ```