tstr/
tstr_type.rs

1use core::{
2    fmt::{self, Debug},
3    marker::PhantomData,
4};
5
6/// A type-level string type, similar to a `&'static str` const parameter.
7///
8/// # Examples
9///
10/// ### Accessing Fields
11///
12/// This example demonstrates how you can use `TStr` to implement a generic accessor trait.
13///
14/// ```rust
15/// use tstr::TStr;
16/// use tstr::{TS, ts};
17///
18/// fn main() {
19///     let mut tup = (3, 5, 8);
20///     
21///     assert_eq!(tup.get(ts!(0)), &3);
22///     assert_eq!(tup.get(ts!(1)), &5);
23///     assert_eq!(tup.get(ts!(2)), &8);
24///
25///     let old_0 = replace(&mut tup, ts!(0), 333);
26///     let old_1 = replace(&mut tup, ts!(1), 555);
27///     let old_2 = replace(&mut tup, ts!(2), 888);
28///     
29///     assert_eq!(tup.get(ts!(0)), &333);
30///     assert_eq!(tup.get(ts!(1)), &555);
31///     assert_eq!(tup.get(ts!(2)), &888);
32///
33///     assert_eq!(old_0, 3);
34///     assert_eq!(old_1, 5);
35///     assert_eq!(old_2, 8);
36///     
37/// }
38///
39/// fn replace<T, N>(this: &mut T, name: TStr<N>, replacement: T::Field) -> T::Field
40/// where
41///     T: Access<TStr<N>>,
42///     T::Field: Clone,
43/// {
44///     let ret = this.get(name).clone();
45///     this.set(name, replacement);
46///     ret
47/// }
48///
49///
50/// trait Access<N> {
51///     type Field;
52///
53///     fn get(&self, _field_name: N) -> &Self::Field;
54///     fn set(&mut self, _field_name: N, val: Self::Field);
55/// }
56///
57/// impl<A, B, C> Access<TS!(0)> for (A, B, C) {
58///     type Field = A;
59///
60///     fn get(&self, _field_name: TS!(0)) -> &A {
61///         &self.0
62///     }
63///     fn set(&mut self, _field_name: TS!(0), val: A){
64///         self.0 = val;
65///     }
66/// }
67///
68/// impl<A, B, C> Access<TS!(1)> for (A, B, C) {
69///     type Field = B;
70///
71///     fn get(&self, _field_name: TS!(1)) -> &B {
72///         &self.1
73///     }
74///     fn set(&mut self, _field_name: TS!(1), val: B){
75///         self.1 = val;
76///     }
77/// }
78///
79/// impl<A, B, C> Access<TS!(2)> for (A, B, C) {
80///     type Field = C;
81///
82///     fn get(&self, _field_name: TS!(2)) -> &C {
83///         &self.2
84///     }
85///     fn set(&mut self, _field_name: TS!(2), val: C){
86///         self.2 = val;
87///     }
88/// }
89///
90/// ```
91///
92pub struct TStr<T>(pub(crate) PhantomData<fn() -> T>);
93
94impl<T> TStr<T> {
95    /// Constructs the TStr.
96    ///
97    /// # Example
98    ///
99    /// ```rust
100    /// use tstr::{TS, TStr};
101    ///
102    /// type FOO = TS!(foo);
103    ///
104    /// let foo_1: FOO = TStr::NEW;
105    /// let foo_2 = FOO::NEW; // The same as the previous statement
106    ///
107    /// ```
108    pub const NEW: Self = TStr(PhantomData);
109}
110
111#[cfg(feature = "const_generics")]
112macro_rules! const_generics_using {
113    () => {
114        /// For getting the `&'static str` value of this [`TStr`].
115        ///
116        /// You can use this as the bound for a generic [`TStr`] parameter.
117        ///
118        /// # Example
119        ///
120        /// ```rust
121        /// use tstr::{StrValue, ts};
122        ///
123        /// asserts(ts!(foo), ts!(bar), ts!(baz));
124        ///
125        /// fn asserts<A, B, C>(foo: A, bar: B, baz: C)
126        /// where
127        ///     A: StrValue,
128        ///     B: StrValue,
129        ///     C: StrValue,
130        /// {
131        ///     assert_eq!(A::STR, "foo");
132        ///     assert_eq!(foo.to_str(), "foo");
133        ///
134        ///     assert_eq!(B::STR, "bar");
135        ///     assert_eq!(bar.to_str(), "bar");
136        ///
137        ///     assert_eq!(C::STR, "baz");
138        ///     assert_eq!(baz.to_str(), "baz");
139        ///
140        /// }
141        ///
142        /// ```
143        ///
144        /// [`TStr`]: ./struct.TStr.html
145        #[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_generics")))]
146        pub trait StrValue: Debug + Copy + Default + 'static {
147            /// The `&'static str` value of this `TStr`.
148            const STR: &'static str;
149
150            /// Gets the `&'static str` value of this `TStr`.
151            fn to_str(self) -> &'static str {
152                Self::STR
153            }
154        }
155
156        #[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_generics")))]
157        impl<const S: &'static str> StrValue for TStr<crate::___<S>> {
158            const STR: &'static str = S;
159        }
160
161        #[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_generics")))]
162        impl<T> TStr<T>
163        where
164            Self: StrValue,
165        {
166            /// The `&'static str` value of this `TStr`.
167            ///
168            /// # Example
169            ///
170            /// ```rust
171            /// use tstr::TS;
172            ///
173            /// type FOO = TS!(foo);
174            /// type BAR = TS!(bar);
175            ///
176            /// assert_eq!(FOO::STR, "foo");
177            /// assert_eq!(BAR::STR, "bar");
178            ///
179            /// ```
180            pub const STR: &'static str = <Self as StrValue>::STR;
181        }
182    };
183}
184#[cfg(feature = "const_generics")]
185const_generics_using! {}
186
187impl<T> Copy for TStr<T> {}
188
189impl<T> Clone for TStr<T> {
190    #[inline(always)]
191    fn clone(&self) -> Self {
192        *self
193    }
194}
195
196impl<T> Default for TStr<T> {
197    #[inline(always)]
198    fn default() -> Self {
199        Self::NEW
200    }
201}
202
203impl<T> Debug for TStr<T> {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        f.debug_struct("TStr").finish()
206    }
207}
208
209impl<T> core::cmp::PartialEq for TStr<T> {
210    #[inline(always)]
211    fn eq(&self, _other: &Self) -> bool {
212        true
213    }
214}
215
216impl<T> core::cmp::Eq for TStr<T> {}
217
218impl<T> core::cmp::PartialOrd for TStr<T> {
219    #[inline(always)]
220    fn partial_cmp(&self, _other: &Self) -> Option<core::cmp::Ordering> {
221        Some(core::cmp::Ordering::Equal)
222    }
223}
224
225impl<T> core::cmp::Ord for TStr<T> {
226    #[inline(always)]
227    fn cmp(&self, _other: &Self) -> core::cmp::Ordering {
228        core::cmp::Ordering::Equal
229    }
230}