tstr/asserts.rs
1//! Types for asserting properties of type-level strings.
2
3use core::marker::PhantomData;
4
5/// For asserting the (in)equality of two type-level strings.
6///
7/// # Warning
8///
9/// From testing the associated constants from this type,
10/// these assertions might not be evaluated in functions that
11/// aren't reachable by public functions.
12///
13/// # Examples
14///
15/// For examples, you can look at each associated constant below.
16///
17///
18///
19pub struct Assert<A, B>(core::marker::PhantomData<(A, B)>);
20
21#[cfg(feature = "cmp_traits")]
22#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp_traits")))]
23impl<A, B> Assert<A, B>
24where
25 A: crate::TStrEq<B>,
26{
27 /// Asserts that the `A` and `B` type-level strings compare equal.
28 pub const EQUAL: EqualityProof<A, B> = {
29 ["Expected the type parameters to be equal"][A::NE as usize];
30 EqualityProof(PhantomData)
31 };
32}
33
34#[cfg(feature = "cmp_traits")]
35#[cfg_attr(feature = "docsrs", doc(cfg(feature = "cmp_traits")))]
36impl<A, B> Assert<A, B>
37where
38 A: crate::TStrEq<B>,
39{
40 /// Asserts that the `A` and `B` type-level strings compare not equal.
41 ///
42 /// # Example
43 ///
44 /// This uses types from the `for_examples` module,
45 /// which can be seen in the docs with the "for_examples" feature.
46 ///
47 /// ```rust
48 /// use tstr::for_examples::Foo;
49 /// use tstr::{Assert, ts};
50 ///
51 /// use std::ops::Index;
52 ///
53 /// let this = Foo::new(3, 5, "8");
54 ///
55 /// assert_eq!(this.get_two(ts!(bar), ts!(qux), Assert::NOT_EQUAL), (&3, &"8"))
56 ///
57 /// ```
58 ///
59 /// The same method call errors when we try to get two references to the same field.
60 // For some reason it fails to compile with ```rust
61 // but compiles without errors with ```compile_fail (causing a cargo test failure)
62 /// ```ignore
63 /// use tstr::for_examples::Foo;
64 /// use tstr::{Assert, ts};
65 /// use std::ops::Index;
66 ///
67 /// # pub fn main() {
68 ///
69 /// let this = Foo::new(3, 5, "8");
70 ///
71 /// assert_eq!(this.get_two(ts!(bar), ts!(bar), Assert::NOT_EQUAL), (&3, &3))
72 ///
73 /// # }
74 /// ```
75 ///
76 /// Truncated error:
77 /// ```text
78 /// error[E0080]: erroneous constant used
79 /// --> src/asserts.rs:55:45
80 /// |
81 /// 11 | assert_eq!(this.get_two(ts!(bar), ts!(bar), Assert::NOT_EQUAL), (&3, &3))
82 /// | ^^^^^^^^^^^^^^^^^ referenced constant has errors
83 ///
84 /// ```
85 ///
86 pub const NOT_EQUAL: InequalityProof<A, B> = {
87 ["Expected the type parameters to not be equal"][A::EQ as usize];
88 InequalityProof(PhantomData)
89 };
90}
91
92macro_rules! declare_assert_res {
93 (
94 $(#[$meta:meta])*
95 struct $struct:ident<$L:ident, $R:ident>;
96 )=> {
97 $(#[$meta])*
98 pub struct $struct<$L, $R>(PhantomData<($L, $R)>);
99
100 impl<$L, $R> Copy for $struct<$L, $R> {}
101
102 impl<$L, $R> Clone for $struct<$L, $R> {
103 fn clone(&self) -> Self {
104 *self
105 }
106 }
107
108 impl<$L, $R> $struct<$L, $R> {
109 /// Infers the type parameters by passing them as arguments.
110 pub const fn infer(self, _: &$L, _: &$R){}
111 }
112 };
113}
114
115#[cfg(feature = "cmp_traits")]
116declare_assert_res! {
117 /// Value-level proof that the `L` and `R` type-level strings compared equal.
118 ///
119 /// Constructed with [`Àssert::EQUAL`]
120 ///
121 /// [`Àssert::EQUAL`]: ./struct.Assert.html#associatedconstant.EQUAL
122 struct EqualityProof<L,R>;
123}
124
125#[cfg(feature = "cmp_traits")]
126declare_assert_res! {
127 /// Value-level proof that the `L` and `R` type-level strings compared not equal.
128 ///
129 /// Constructed with [`Àssert::NOT_EQUAL`]
130 ///
131 /// [`Àssert::NOT_EQUAL`]: ./struct.Assert.html#associatedconstant.NOT_EQUAL
132 struct InequalityProof<L, R>;
133}