typewit/const_marker/boolwit.rs
1use core::fmt::{self, Debug};
2
3use crate::{
4 const_marker::Bool,
5 TypeCmp,
6 TypeEq,
7 TypeWitnessTypeArg, MakeTypeWitness,
8};
9
10
11/// Type Witness that [`Bool<B>`](Bool) is either `Bool<true>` or `Bool<false>`.
12///
13/// Use this over [`BoolWitG`] if you have a `const B: bool` parameter already.
14///
15/// # Example
16///
17/// Making a function that takes a generic `Foo<B>` and calls methods on
18/// `Foo<false>` or `Foo<true>` depending on the value of the `const B: bool` parameter.
19///
20/// ```rust
21/// use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness};
22///
23///
24/// assert_eq!(call_next(Incrementor::<GO_UP>(4)), Incrementor(5));
25/// assert_eq!(call_next(Incrementor::<GO_UP>(5)), Incrementor(6));
26///
27/// assert_eq!(call_next(Incrementor::<GO_DOWN>(4)), Incrementor(3));
28/// assert_eq!(call_next(Incrementor::<GO_DOWN>(3)), Incrementor(2));
29///
30///
31/// const fn call_next<const B: bool>(incrementor: Incrementor<B>) -> Incrementor<B> {
32/// typewit::type_fn! {
33/// // type-level function from `Bool<B>` to `Incrementor<B>`
34/// struct IncrementorFn;
35/// impl<const B: bool> Bool<B> => Incrementor<B>
36/// }
37///
38/// // The example below this one shows how to write this match more concisely
39/// match BoolWit::MAKE {
40/// // `bw: TypeEq<Bool<B>, Bool<true>>`
41/// BoolWit::True(bw) => {
42/// // `te: TypeEq<Incrementor<B>, Incrementor<true>>`
43/// let te = bw.project::<IncrementorFn>();
44///
45/// // `te.to_right` casts `Incrementor<B>` to `Incrementor<true>`,
46/// // (this allows calling the inherent method).
47/// //
48/// // `te.to_left` casts `Incrementor<true>` to `Incrementor<B>`
49/// te.to_left(te.to_right(incrementor).next())
50/// }
51/// // `bw: TypeEq<Bool<B>, Bool<false>>`
52/// BoolWit::False(bw) => {
53/// // `te: TypeEq<Incrementor<B>, Incrementor<false>>`
54/// let te = bw.project::<IncrementorFn>();
55///
56/// // like the other branch, but with `Incrementor<false>`
57/// te.to_left(te.to_right(incrementor).next())
58/// }
59/// }
60/// }
61///
62///
63/// #[derive(Debug, Copy, Clone, PartialEq, Eq)]
64/// struct Incrementor<const GO_UP: bool>(usize);
65///
66/// const GO_UP: bool = true;
67/// const GO_DOWN: bool = false;
68///
69/// impl Incrementor<GO_DOWN> {
70/// #[track_caller]
71/// pub const fn next(self) -> Self {
72/// Self(self.0 - 1)
73/// }
74/// }
75///
76/// impl Incrementor<GO_UP> {
77/// pub const fn next(self) -> Self {
78/// Self(self.0 + 1)
79/// }
80/// }
81///
82/// ```
83///
84/// ### Using `polymatch` for conciseness
85///
86/// The [`polymatch`](crate::polymatch) macro can be used to
87/// more concisely implement the `call_next` function.
88///
89/// ```
90/// # use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness};
91/// #
92/// const fn call_next<const B: bool>(incrementor: Incrementor<B>) -> Incrementor<B> {
93/// typewit::type_fn! {
94/// struct IncrementorFn;
95/// impl<const B: bool> Bool<B> => Incrementor<B>
96/// }
97///
98/// // expands to a match with two arms,
99/// // one for `BoolWit::True` and one for `BoolWit::False`,
100/// // copying the expression to the right of the `=>` to both arms.
101/// typewit::polymatch! {BoolWit::MAKE;
102/// BoolWit::True(bw) | BoolWit::False(bw) => {
103/// let te = bw.project::<IncrementorFn>();
104/// te.to_left(te.to_right(incrementor).next())
105/// }
106/// }
107/// }
108/// #
109/// # #[derive(Debug, Copy, Clone, PartialEq, Eq)]
110/// # struct Incrementor<const GO_UP: bool>(usize);
111/// #
112/// # const GO_UP: bool = true;
113/// # const GO_DOWN: bool = false;
114/// #
115/// # impl Incrementor<GO_DOWN> {
116/// # #[track_caller]
117/// # pub const fn next(self) -> Self { unimplemented!() }
118/// # }
119/// #
120/// # impl Incrementor<GO_UP> {
121/// # pub const fn next(self) -> Self { unimplemented!() }
122/// # }
123/// ```
124///
125/// ### What happens without `BoolWit`
126///
127/// If the `call_next` function was defined like this:
128/// ```rust,compile_fail
129/// # use typewit::{const_marker::{Bool, BoolWit}, MakeTypeWitness};
130/// #
131/// const fn call_next<const B: bool>(incrementor: Incrementor<B>) -> Incrementor<B> {
132/// incrementor.next()
133/// }
134/// # #[derive(Copy, Clone)]
135/// # struct Incrementor<const WRAPPING: bool>(usize);
136/// #
137/// # impl Incrementor<false> {
138/// # pub const fn next(self) -> Self {
139/// # unimplemented!()
140/// # }
141/// # }
142/// #
143/// # impl Incrementor<true> {
144/// # pub const fn next(self) -> Self {
145/// # unimplemented!()
146/// # }
147/// # }
148/// ```
149/// it would produce this error
150/// ```text
151/// error[E0599]: no method named `next` found for struct `Incrementor<B>` in the current scope
152/// --> src/const_marker/const_witnesses.rs:20:17
153/// |
154/// 7 | incrementor.next()
155/// | ^^^^ method not found in `Incrementor<B>`
156/// ...
157/// 38 | struct Incrementor<const WRAPPING: bool>(usize);
158/// | ---------------------------------------- method `next` not found for this struct
159/// |
160/// = note: the method was found for
161/// - `Incrementor<false>`
162/// - `Incrementor<true>`
163/// ```
164///
165///
166pub type BoolWit<const B: bool> = BoolWitG<Bool<B>>;
167
168
169/// Type witness that `B` is either [`Bool`]`<true>` or [`Bool`]`<false>`
170///
171/// Use this over [`BoolWit`] if you want to write a [`HasTypeWitness`] bound
172/// and adding a `const B: bool` parameter would be impossible.
173///
174/// # Example
175///
176/// This basic example demonstrates where `BoolWitG` would be used instead of `BoolWit`.
177///
178/// ```rust
179/// use typewit::const_marker::{Bool, BoolWitG};
180/// use typewit::HasTypeWitness;
181///
182///
183/// trait Boolean: Sized + HasTypeWitness<BoolWitG<Self>> {
184/// type Not: Boolean<Not = Self>;
185/// }
186///
187/// impl Boolean for Bool<true> {
188/// type Not = Bool<false>;
189/// }
190///
191/// impl Boolean for Bool<false> {
192/// type Not = Bool<true>;
193/// }
194/// ```
195///
196/// [`HasTypeWitness`]: crate::HasTypeWitness
197pub enum BoolWitG<B> {
198 /// Witnesses that `B == true`
199 True(TypeEq<B, Bool<true>>),
200 /// Witnesses that `B == false`
201 False(TypeEq<B, Bool<false>>),
202}
203
204impl<B> BoolWitG<B> {
205 /// Whether `B == Bool<true>`
206 ///
207 /// # Example
208 ///
209 /// ```rust
210 /// use typewit::{const_marker::BoolWitG, TypeEq};
211 ///
212 /// assert_eq!(BoolWitG::True(TypeEq::NEW).is_true(), true);
213 /// assert_eq!(BoolWitG::False(TypeEq::NEW).is_true(), false);
214 /// ```
215 ///
216 pub const fn is_true(self) -> bool {
217 matches!(self, Self::True{..})
218 }
219
220 /// Whether `B == Bool<false>`
221 ///
222 /// # Example
223 ///
224 /// ```rust
225 /// use typewit::{const_marker::BoolWitG, TypeEq};
226 ///
227 /// assert_eq!(BoolWitG::True(TypeEq::NEW).is_false(), false);
228 /// assert_eq!(BoolWitG::False(TypeEq::NEW).is_false(), true);
229 /// ```
230 ///
231 pub const fn is_false(self) -> bool {
232 matches!(self, Self::False{..})
233 }
234
235 /// Gets a proof of `B == Bool<true>`, returns None if `B == Bool<false>`
236 ///
237 /// # Example
238 ///
239 /// ```rust
240 /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq};
241 ///
242 /// assert_eq!(BoolWitG::True(TypeEq::NEW).to_true(), Some(TypeEq::new::<Bool<true>>()));
243 /// assert_eq!(BoolWitG::False(TypeEq::NEW).to_true(), None);
244 /// ```
245 ///
246 pub const fn to_true(self) -> Option<TypeEq<B, Bool<true>>> {
247 match self {
248 Self::True(x) => Some(x),
249 Self::False{..} => None
250 }
251 }
252
253 /// Gets a proof of `B == Bool<false>`, returns None if `B == Bool<true>`
254 ///
255 /// # Example
256 ///
257 /// ```rust
258 /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq};
259 ///
260 /// assert_eq!(BoolWitG::True(TypeEq::NEW).to_false(), None);
261 /// assert_eq!(BoolWitG::False(TypeEq::NEW).to_false(), Some(TypeEq::new::<Bool<false>>()));
262 /// ```
263 ///
264 pub const fn to_false(self) -> Option<TypeEq<B, Bool<false>>> {
265 match self {
266 Self::False(x) => Some(x),
267 Self::True{..} => None
268 }
269 }
270
271
272 /// Gets a proof of `B == Bool<true>`.
273 ///
274 /// # Panic
275 ///
276 /// Panics if `B == Bool<false>`
277 ///
278 /// # Example
279 ///
280 /// ```rust
281 /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq};
282 ///
283 /// assert_eq!(BoolWitG::True(TypeEq::NEW).unwrap_true(), TypeEq::new::<Bool<true>>());
284 /// ```
285 ///
286 pub const fn unwrap_true(self) -> TypeEq<B, Bool<true>> {
287 match self {
288 Self::True(x) => x,
289 Self::False{..} => panic!("attempted to unwrap into True on False variant")
290 }
291 }
292
293 /// Gets a proof of `B == Bool<false>`.
294 ///
295 /// # Panic
296 ///
297 /// Panics if `B == Bool<true>`
298 ///
299 /// # Example
300 ///
301 /// ```rust
302 /// use typewit::{const_marker::{Bool, BoolWitG}, TypeEq};
303 ///
304 /// assert_eq!(BoolWitG::False(TypeEq::NEW).unwrap_false(), TypeEq::new::<Bool<false>>());
305 /// ```
306 ///
307 pub const fn unwrap_false(self) -> TypeEq<B, Bool<false>> {
308 match self {
309 Self::False(x) => x,
310 Self::True{..} => panic!("attempted to unwrap into False on True variant")
311 }
312 }
313
314}
315
316impl<B> Copy for BoolWitG<B> {}
317
318impl<B> Clone for BoolWitG<B> {
319 fn clone(&self) -> Self {
320 *self
321 }
322}
323
324impl<B> Debug for BoolWitG<B> {
325 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326 f.write_str(match self {
327 Self::True{..} => "True",
328 Self::False{..} => "False",
329 })
330 }
331}
332
333impl<B> TypeWitnessTypeArg for BoolWitG<B> {
334 type Arg = B;
335}
336
337impl<const B: bool> MakeTypeWitness for BoolWitG<Bool<B>> {
338 const MAKE: Self = {
339 if let TypeCmp::Eq(te) = Bool.equals(Bool) {
340 BoolWit::True(te)
341 } else if let TypeCmp::Eq(te) = Bool.equals(Bool) {
342 BoolWit::False(te)
343 } else {
344 panic!("unreachable: `B` is either `true` or `false`")
345 }
346 };
347}
348