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