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}