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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Niche optimisation for FFI-wire encodings.
//!
//! A *niche* is a bit-pattern that the wire type *can* represent but that
//! a particular converter is guaranteed to never produce on output and
//! always reject on input. Wrappers like `Option<_>` and sum-typed enums
//! carve niches one at a time for their own discriminants and re-export
//! the remainder so further wrappers stack.
//!
//! Direct analogy with Rust's niche optimisation:
//!
//! | Rust | This crate |
//! | ---------------------------- | --------------------------------------- |
//! | `NonZeroU32` declares `{0}` | converter sets `niches = Niches::one(…)`|
//! | `Option<NonZeroU32>` is u32 | `Option<T>` reuses inner's wire |
//! | `Option<Option<NonZeroU32>>` | falls back unless inner exposes ≥2 |
//!
//! In the FFI setting the canonical example is a Rust value encoded as a
//! raw `Box::into_raw` pointer carried over the wire as an integer handle:
//! real `Box::into_raw` results are never `0`, so the converter declares
//! the single niche `{0}`. `Option<T>` then automatically reuses the same
//! integer wire with `0` meaning `None`, matching the C-pointer-with-null
//! ABI most native bindings already use.
//!
//! ## Cascading
//!
//! [`Niches::carve`] returns the next slot together with the remainder.
//! The wrapper places the carved value into its own emitted code (output:
//! `None` is encoded as `slot.value`; input: `slot.matches` is the
//! discriminator predicate) and stores `rest` on its own
//! [`crate::prebindgen::ConverterImpl::niches`] so any
//! enclosing wrapper can keep carving. Once `rest` is empty further
//! wrappers must fall back to a tag/box scheme.
//!
//! ## Soundness
//!
//! For the carve to be sound, the inner converter's outputs must
//! genuinely avoid the carved bit pattern, and its input must reject it
//! (typically by erroring). The adapter author guarantees this — `Niches`
//! is a *declaration* that the resolver and wrappers trust.
//!
//! ## Calling convention for `matches`
//!
//! The `matches` predicate is spliced into the input wrapper's body where
//! the wire-typed parameter `v` is in scope. The exact shape of `v`
//! depends on the wire kind:
//!
//! * By-reference wires (e.g. an integer handle, or an object-handle
//! type): `v: &<wire>` — write `*v == 0`, or `v.is_null()` for a handle
//! type that derefs to a null check.
//! * Raw-pointer wires (`*const T`): `v: <wire>` — write `v.is_null()`
//! directly, no `*` deref.
//!
//! The adapter producing the niche knows which wire kind it is using and
//! must write `matches` accordingly.
//!
//! `value` is a wire-typed *constant* expression with no `v` and no other
//! locals in scope — just the bit pattern (e.g. `0i64`,
//! `std::ptr::null()`).
/// One free bit-pattern slot in the wire encoding.
///
/// See the module-level docs for the calling convention of `matches` and
/// `value`.
/// An ordered set of [`NicheSlot`]s that a converter's wire type can
/// represent but that this converter never produces (output) and always
/// rejects (input).
///
/// Ordering: the *first* slot is the next one taken by [`Self::carve`].
/// Wrappers carve from the front; the remaining slots are passed up so
/// that further wrappers can stack their own discriminants.