tstr/
tstr_trait.rs

1use crate::{__TStrRepr, TStr};
2
3use core::{
4    cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
5    fmt::{Debug, Display},
6    hash::Hash,
7};
8
9use typewit::Identity;
10
11/// Many associated items of the [`TStr`] type-level string,
12/// as well as supertraits for traits implemented by it.
13///
14/// This trait is sealed and cannot be implemented outside of the `tstr` crate.
15pub trait IsTStr:
16    Identity<Type = TStr<<Self as IsTStr>::Arg>>
17    + 'static
18    + crate::strlike::StrLike<__TStr = Self>
19    + Copy
20    + Clone
21    + Debug
22    + Display
23    + Default
24    + Hash
25    + Eq
26    + Ord
27    + PartialEq
28    + PartialEq<str>
29    + for<'a> PartialEq<&'a str>
30    + for<'a, 'b> PartialEq<&'a &'b str>
31    + PartialOrd
32    + PartialOrd<str>
33    + for<'a, 'b> PartialOrd<&'a &'b str>
34    + Send
35    + Sized
36    + Sync
37    + core::marker::Unpin
38{
39    /// The type parameter of `TStr`
40    type Arg: TStrArg;
41
42    /// Constructs this `IsTStr`
43    const VAL: Self;
44
45    /// The length of this string when encoded to utf8
46    const LENGTH: usize;
47
48    /// This string converted to a uf8-encoded byte slice
49    const BYTES: &[u8];
50
51    /// This type-level string converted to a string
52    const STR: &str;
53
54    /// Coerces `Self` to `TStr<Self::Arg>`, only necessary in generic contexts
55    ///
56    /// The const equivalent of this trait method is the
57    /// [`TStr::from_gen`](crate::TStr::from_gen) constructor.
58    ///
59    /// While it's always possible to construct a `TStr` through its
60    /// [`new`](crate::TStr::new) constructor,
61    /// this method ensures that it's the same string as `Self`.
62    ///
63    /// # Example
64    ///
65    /// ```rust
66    /// use tstr::{IsTStr, TStr};
67    ///
68    /// #[repr(transparent)]
69    /// struct Foo<T, N: IsTStr> {
70    ///     val: T,
71    ///     // since TStr is zero-sized, it can be put in `#[repr(transparent)]` types
72    ///     // next to the wrapped non-Zero-Sized-Type.
73    ///     name: TStr<N::Arg>,
74    /// }
75    ///
76    /// impl<T, N: IsTStr> Foo<T, N> {
77    ///     pub fn new(val: T, tstr: N) -> Self {
78    ///         Self{ val, name: tstr.to_tstr() }
79    ///     }
80    /// }
81    /// ```
82    ///
83    fn to_tstr(self) -> TStr<Self::Arg> {
84        <Self as Identity>::TYPE_EQ.to_right(self)
85    }
86
87    /// Coerces a `TStr` into `Self`, only necessary in generic contexts.
88    ///
89    /// The const equivalent of this trait method is the
90    /// [`TStr::to_gen`](crate::TStr::to_gen) method.
91    ///
92    /// While it's always possible to construct `Self` through the
93    /// [`VAL`](crate::IsTStr::VAL) associated constant,
94    /// this function ensures that it's the same string as the argument.
95    ///
96    /// # Example
97    ///
98    /// ```rust
99    /// use tstr::{IsTStr, TStr};
100    ///
101    /// #[repr(transparent)]
102    /// struct Foo<T, N: IsTStr> {
103    ///     val: T,
104    ///     name: TStr<N::Arg>,
105    /// }
106    ///
107    /// impl<T, N: IsTStr> Foo<T, N> {
108    ///     fn name(&self) -> N {
109    ///         N::from_tstr(self.name)
110    ///     }
111    /// }
112    /// ```
113    ///
114    fn from_tstr(tstr: TStr<Self::Arg>) -> Self {
115        <Self as Identity>::TYPE_EQ.to_left(tstr)
116    }
117
118    /// Gets the length of the string in utf8
119    ///
120    /// The const equivalent of this trait is the
121    /// [`tstr::len`](crate::len) function.
122    ///
123    /// # Example
124    ///
125    /// ```rust
126    /// use tstr::{IsTStr, ts};
127    ///
128    /// assert!(ts!(4).len() == 1);
129    ///
130    /// assert!(ts!("hello").len() == 5);
131    ///
132    /// assert!(ts!(rustacean).len() == 9);
133    ///
134    /// ```
135    fn len(self) -> usize {
136        Self::LENGTH
137    }
138
139    /// Gets the `&'static str` equivalent of this [`TStr`]
140    ///
141    /// The const equivalent of this trait is the
142    /// [`tstr::to_str`](crate::to_str) function.
143    ///
144    /// # Example
145    ///
146    /// ```rust
147    /// use tstr::{IsTStr, TStr, ts};
148    ///
149    /// let foo: TStr<_> = ts!(foo);
150    /// assert_eq!(foo.to_str(), "foo");
151    ///
152    /// let bar_str: &str = ts!("bar").to_str();
153    /// assert_eq!(bar_str, "bar");
154    ///
155    /// ```
156    ///
157    fn to_str(self) -> &'static str {
158        Self::STR
159    }
160
161    /// Gets the `&'static [u8]` equivalent of this [`TStr`]
162    ///
163    /// The const equivalent of this trait is the
164    /// [`tstr::to_bytes`](crate::to_bytes) function.
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// use tstr::{IsTStr, TStr, ts};
170    ///
171    /// let foo: TStr<_> = ts!(foo);
172    /// assert_eq!(foo.to_bytes(), "foo".as_bytes());
173    ///
174    /// let bar_str: &[u8] = ts!("bar").to_bytes();
175    /// assert_eq!(bar_str, "bar".as_bytes());
176    ///
177    /// ```
178    ///
179    fn to_bytes(self) -> &'static [u8] {
180        Self::BYTES
181    }
182
183    /// Compares two [`TStr`]s for equality
184    ///
185    /// The const equivalent of this trait is the
186    /// [`tstr::eq`](crate::eq) function.
187    ///
188    /// This method exists to allow comparing any `TStr` to any other,
189    /// because the `for<Rhs: IsTStr> PartialEq<Rhs>` supertrait can't be written on stable.
190    ///
191    /// # Examples
192    ///
193    /// ```rust
194    /// use tstr::{IsTStr, ts};
195    ///
196    /// assert!( ts!("foo").tstr_eq(ts!("foo")));
197    ///
198    /// assert!(!ts!("foo").tstr_eq(ts!("bar")));
199    ///
200    /// ```
201    ///
202    fn tstr_eq<Rhs: IsTStr>(self, rhs: Rhs) -> bool {
203        crate::eq(self, rhs)
204    }
205
206    /// Compares two [`TStr`]s for inequality
207    ///
208    /// The const equivalent of this trait is the
209    /// [`tstr::ne`](crate::ne) function.
210    ///
211    /// This method exists to allow comparing any `TStr` to any other,
212    /// because the `for<Rhs: IsTStr> PartialEq<Rhs>` supertrait can't be written on stable.
213    ///
214    /// # Examples
215    ///
216    /// ```rust
217    /// use tstr::{IsTStr, ts};
218    ///
219    /// assert!(!ts!("foo").tstr_ne(ts!("foo")));
220    ///
221    /// assert!( ts!("foo").tstr_ne(ts!("bar")));
222    ///
223    /// ```
224    ///
225    fn tstr_ne<Rhs: IsTStr>(self, rhs: Rhs) -> bool {
226        crate::ne(self, rhs)
227    }
228
229    /// Compares two [`TStr`]s for ordering
230    ///
231    /// The const equivalent of this trait is the
232    /// [`tstr::cmp`](crate::cmp) function.
233    ///
234    /// This method exists to allow comparing any `TStr` to any other,
235    /// because the `for<Rhs: IsTStr> PartialOrd<Rhs>` supertrait can't be written on stable.
236    ///
237    /// # Examples
238    ///
239    /// ```rust
240    /// use tstr::{IsTStr, ts};
241    /// use core::cmp::Ordering;
242    ///
243    /// assert_eq!(ts!("foo").tstr_cmp(ts!("foo")), Ordering::Equal);
244    ///
245    /// assert_eq!(ts!("foo").tstr_cmp(ts!("bar")), Ordering::Greater);
246    ///
247    /// assert_eq!(ts!("bar").tstr_cmp(ts!("foo")), Ordering::Less);
248    ///
249    /// ```
250    ///
251    fn tstr_cmp<Rhs: IsTStr>(self, rhs: Rhs) -> Ordering {
252        crate::cmp(self, rhs)
253    }
254
255    /// Compares two [`TStr`]s for equality,
256    /// returning a proof of (in)equality of `Self` and `Rhs`
257    ///
258    /// The const equivalent of this trait is the
259    /// [`tstr::type_eq`](crate::type_eq) function.
260    ///
261    /// # Example
262    ///
263    /// ```rust
264    /// use tstr::{IsTStr, TStr, TS, ts};
265    /// use tstr::typewit::TypeCmp;
266    ///
267    ///
268    /// assert_eq!(is_right_guess(Guess(ts!(foo))), None);
269    /// assert_eq!(is_right_guess(Guess(ts!(bar))), None);
270    /// assert_eq!(is_right_guess(Guess(ts!(world))), None);
271    ///
272    /// assert!(is_right_guess(Guess(ts!(hello))).is_some_and(|x| x.0 == "hello"));
273    ///
274    /// #[derive(Debug, PartialEq, Eq)]
275    /// struct Guess<S: IsTStr>(S);
276    ///
277    /// fn is_right_guess<S: IsTStr>(guess: Guess<S>) -> Option<Guess<impl IsTStr>> {
278    ///     let ret: Option<Guess<TS!(hello)>> = typecast_guess(guess).ok();
279    ///     ret
280    /// }
281    ///
282    /// /// Coerces `Guess<A>` to `Guess<B>` if `A == B`, returns `Err(guess)` if `A != B`.
283    /// fn typecast_guess<A, B>(guess: Guess<A>) -> Result<Guess<B>, Guess<A>>
284    /// where
285    ///     A: IsTStr,
286    ///     B: IsTStr,
287    /// {
288    ///     tstr::typewit::type_fn!{
289    ///         // type-level function from `S` to `Guess<S>`
290    ///         struct GuessFn;
291    ///         impl<S: IsTStr> S => Guess<S>
292    ///     }
293    ///     
294    ///     match A::VAL.type_eq(B::VAL) {
295    ///         TypeCmp::Eq(te) => Ok(
296    ///             // te is a `TypeEq<A, B>`, a value-level proof that both args are the same type.
297    ///             te               
298    ///             .map(GuessFn)    // : TypeEq<Guess<A>, Guess<B>>
299    ///             .to_right(guess) // : Guess<B>
300    ///         ),
301    ///         TypeCmp::Ne(_) => Err(guess),
302    ///     }
303    /// }
304    ///
305    ///
306    /// ```
307    ///
308    fn type_eq<Rhs: IsTStr>(self, rhs: Rhs) -> typewit::TypeCmp<Self, Rhs> {
309        crate::type_eq(self, rhs)
310    }
311}
312
313impl<S> IsTStr for TStr<S>
314where
315    S: TStrArg,
316{
317    type Arg = S;
318
319    const VAL: Self = Self::new();
320
321    const LENGTH: usize = S::__LENGTH;
322
323    const BYTES: &[u8] = S::__BYTES;
324
325    const STR: &str = S::__STR;
326}
327
328/// For bounding the type parameter of [`TStr`].
329///
330/// You only need this trait if you're using using `TStr` explicitly in the code,
331/// it's usually better have a type parameter bounded by
332/// the [`IsTStr`] trait instead of using `TStr` directly.
333///
334/// This trait is sealed and cannot be implemented outside of the `tstr` crate.
335///
336/// # Example
337///
338/// This example shows a usecase where you'll need to use this trait,
339/// implementing traits for `TStr`.
340///
341/// ```rust
342/// use tstr::{IsTStr, TStr, TStrArg, ts};
343///
344/// assert_eq!("hello".my_as_str(), "hello");
345/// assert_eq!(ts!(world).my_as_str(), "world");
346///
347///
348/// trait MyAsStr {
349///     fn my_as_str(&self) -> &str;
350/// }
351///
352/// impl MyAsStr for &str {
353///     fn my_as_str(&self) -> &str { self }
354/// }
355///
356/// impl<S: TStrArg> MyAsStr for TStr<S> {
357///     fn my_as_str(&self) -> &str { self.to_str() }
358/// }
359/// ```
360///
361pub trait TStrArg: __TStrRepr + 'static {
362    /// Implementation detail
363    #[doc(hidden)]
364    const __LENGTH: usize;
365
366    /// Implementation detail
367    #[doc(hidden)]
368    const __BYTES: &[u8];
369
370    /// Implementation detail
371    #[doc(hidden)]
372    const __STR: &str;
373
374    /// Implementation detail
375    #[doc(hidden)]
376    type __WithRhs<Rhs: TStrArg>: __TStrArgBinary<Lhs = Self, Rhs = Rhs>;
377
378    /// Implementation detail
379    #[cfg(feature = "str_generics")]
380    #[doc(hidden)]
381    type __WithLhsArgs<const LEFT_S: &'static str>: __TStrArgBinary<Lhs = crate::___<LEFT_S>, Rhs = Self>;
382
383    /// Implementation detail
384    #[cfg(not(feature = "str_generics"))]
385    #[doc(hidden)]
386    type __WithLhsArgs<LeftS: __TStrRepr, const LEFT_LEN: usize>: __TStrArgBinary<Lhs = crate::___<LeftS, LEFT_LEN>, Rhs = Self>;
387}
388
389// implemented for `(Lhs, Rhs)`, does binary operations on a pair of type arguments of TStrs
390#[doc(hidden)]
391pub trait __TStrArgBinary {
392    #[doc(hidden)]
393    type Lhs: __TStrRepr;
394
395    #[doc(hidden)]
396    type Rhs: __TStrRepr;
397
398    #[doc(hidden)]
399    const __EQ: bool;
400
401    #[doc(hidden)]
402    const __CMP: core::cmp::Ordering;
403
404    #[doc(hidden)]
405    const __TYPE_CMP: typewit::TypeCmp<crate::TStr<Self::Lhs>, crate::TStr<Self::Rhs>>;
406}
407
408pub(crate) type __ToTStrArgBinary<L, R> = <L as TStrArg>::__WithRhs<R>;
409
410typewit::inj_type_fn! {
411    pub(crate) struct TStrFn;
412
413    impl<S> S => crate::TStr<S>;
414}