tstr/lib.rs
1//! An encoding of type-level strings, with the [`TStr`] type and related macros.
2//!
3//! This crate features all these on stable:
4//! - a relatively readable default representation of type-level strings
5//! based on `char` const parameters.
6//! - items for converting type-level strings to `&'static str` and `&'static [u8]`
7//! - functions for comparing type-level strings to each other and `&str`
8//! - macros for asserting the (in)equality of type-level strings to each other and `&str`
9//!
10//! All of the above functionality can be used in const contexts.
11//!
12//! # Examples
13//!
14//! ### Indexing
15//!
16//! This example demonstrates how you can use type-level strings,
17//! and the [`Index`] trait, to access fields of generic types by name.
18//!
19//! ```rust
20//! use std::ops::Index;
21//!
22//! use tstr::{TS, ts};
23//!
24//! fn main(){
25//! takes_person(&Person::new("Bob".into(), "Marley".into()));
26//!
27//! takes_person(&OtherPerson::new("Bob", "Marley"));
28//! }
29//!
30//! fn takes_person<P>(pers: &P)
31//! where
32//! P: Index<TS!(name), Output = str> + Index<TS!(surname), Output = str>
33//! {
34//! assert_eq!(&pers[ts!(name)], "Bob");
35//! assert_eq!(&pers[ts!(surname)], "Marley");
36//! }
37//!
38//!
39//! use person::Person;
40//! mod person {
41//! use std::ops::Index;
42//!
43//! use tstr::TS;
44//!
45//! pub struct Person {
46//! name: String,
47//! surname: String,
48//! }
49//!
50//! impl Person {
51//! pub fn new(name: String, surname: String) -> Self {
52//! Self{name, surname}
53//! }
54//! }
55//!
56//! impl Index<TS!(name)> for Person {
57//! type Output = str;
58//!
59//! fn index(&self, _: TS!(name)) -> &str {
60//! &self.name
61//! }
62//! }
63//!
64//! impl Index<TS!(surname)> for Person {
65//! type Output = str;
66//!
67//! fn index(&self, _: TS!(surname)) -> &str {
68//! &self.surname
69//! }
70//! }
71//! }
72//!
73//! use other_person::OtherPerson;
74//! mod other_person {
75//! use std::ops::Index;
76//!
77//! use tstr::TS;
78//!
79//! pub struct OtherPerson {
80//! name: &'static str,
81//! surname: &'static str,
82//! }
83//!
84//! impl OtherPerson {
85//! pub fn new(name: &'static str, surname: &'static str) -> Self {
86//! Self{name, surname}
87//! }
88//! }
89//!
90//! impl Index<TS!(name)> for OtherPerson {
91//! type Output = str;
92//!
93//! fn index(&self, _: TS!(name)) -> &str {
94//! self.name
95//! }
96//! }
97//!
98//! impl Index<TS!(surname)> for OtherPerson {
99//! type Output = str;
100//!
101//! fn index(&self, _: TS!(surname)) -> &str {
102//! self.surname
103//! }
104//! }
105//! }
106//!
107//! ```
108//!
109//! ### Type errors
110//!
111//! This example showcases what TStr looks like in simple type errors.
112//!
113//! ```rust,compile_fail
114//! let _: tstr::TS!("Hello, world!") = ();
115//! ```
116//!
117//! With no crate features enabled, the error message is this:
118//! ```text
119//! error[E0308]: mismatched types
120//! --> tstr/src/lib.rs:114:37
121//! |
122//! 5 | let _: tstr::TS!("Hello, world!") = ();
123//! | -------------------------- ^^ expected `TStr<___<..., 13>>`, found `()`
124//! | |
125//! | expected due to this
126//! |
127//! = note: expected struct `tstr::TStr<___<(tstr::__<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w'>, tstr::__<'o', 'r', 'l', 'd', '!'>, (), (), (), (), (), ()), 13>>`
128//! found unit type `()`
129//! ```
130//! As you can see, the string is represented as a collection of `char` const parameters.
131//!
132//! When the `"nightly_str_generics"` feature is enabled (which requires the nightly compiler),
133//! the error message is this:
134//! ```text
135//! error[E0308]: mismatched types
136//! --> tstr/src/lib.rs:114:37
137//! |
138//! 5 | let _: tstr::TS!("Hello, world!") = ();
139//! | -------------------------- ^^ expected `TStr<___<"Hello, world!">>`, found `()`
140//! | |
141//! | expected due to this
142//! |
143//! = note: expected struct `tstr::TStr<___<"Hello, world!">>`
144//! found unit type `()`
145//! ```
146//!
147//!
148//!
149//! # Macro expansion
150//!
151//! This library reserves the right to change how it represent type-level strings internally
152//! in every single release, and cargo feature combination.
153//!
154//! This only affects you if you expand the code generated by macros from this crate,
155//! and then use that expanded code instead of going through the macros.
156//!
157//! # Cargo features
158//!
159//! - `"const_panic"`(enabled by default):
160//! Enables [`const_panic`] reexports, assertion macros,
161//! and `const_panic::fmt::PanicFmt` impl for `TStr`.
162//!
163//! - `"use_syn"`(disabled by default):
164//! Changes how literals passed to the macros of this crate are parsed to use the `syn` crate.
165//! Use this if there is some literal that could not be
166//! parsed but is a valid str/integer literal.
167//!
168//! - `"str_generics"`(disabled by default):
169//! Changes the representation of type-level strings to use a `&'static str` const parameter,
170//! making for better compiler errors.
171//! As of 2025-08-18, this feature can't be enabled, because it
172//! requires `&'static str` to be stably usable as const parameters.
173//! Consider using `"nightly_str_generics"` if this feature can't be used.
174//!
175//! - `"nightly_str_generics"`(disabled by default): Equivalent to the `"str_generics"` feature,
176//! and enables the nightly compiler features to use `&'static str` const parameters.
177//!
178//! # No-std support
179//!
180//! This crate is unconditionally `#![no_std]`, and can be used anywhere that Rust can be.
181//!
182//! # Minimum Supported Rust Version
183//!
184//! This crate supports Rust versions back to Rust 1.88.0.
185//!
186//! [`TStr`]: crate::TStr
187//! [`const_panic`]: const_panic
188//! [`Index`]: core::ops::Index
189//! [`tstr::utils`]: crate::utils
190#![no_std]
191#![cfg_attr(feature = "nightly_str_generics", feature(adt_const_params))]
192#![cfg_attr(feature = "nightly_str_generics", feature(unsized_const_params))]
193#![cfg_attr(feature = "docsrs", feature(doc_cfg, doc_auto_cfg))]
194#![cfg_attr(feature = "nightly_str_generics", allow(incomplete_features))]
195//////////
196// lints
197//////////
198#![allow(non_camel_case_types)]
199#![forbid(unsafe_code)]
200
201#[cfg(feature = "const_panic")]
202mod assertions;
203
204pub mod strlike;
205
206mod macros;
207mod private_macros;
208
209mod tstr_fns;
210mod tstr_trait;
211mod tstr_type;
212
213#[cfg(not(feature = "str_generics"))]
214mod tstr_impl_with_chars;
215
216#[cfg(not(feature = "str_generics"))]
217pub(crate) use tstr_impl_with_chars::__TStrRepr;
218
219#[cfg(feature = "str_generics")]
220mod tstr_impl_with_str;
221
222#[cfg(feature = "str_generics")]
223pub(crate) use tstr_impl_with_str::__TStrRepr;
224
225pub mod utils;
226
227#[doc(hidden)]
228extern crate self as tstr;
229
230#[doc(hidden)]
231pub use tstr_proc_macros::__ts_impl;
232
233use crate::tstr_trait::__TStrArgBinary;
234
235pub use crate::{
236 tstr_fns::*,
237 tstr_trait::{IsTStr, TStrArg},
238 tstr_type::TStr,
239};
240
241pub use typewit;
242
243#[doc(no_inline)]
244#[cfg(feature = "const_panic")]
245#[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_panic")))]
246pub use const_panic::{self, unwrap_ok as unwrap};
247
248include! {"./p.rs"}
249
250#[doc(hidden)]
251pub mod __p {
252 pub use crate::__Empty;
253 pub use crate::macros::__IgnoreArgReturnEmpty;
254
255 #[cfg(feature = "const_panic")]
256 pub use const_panic::concat_panic;
257
258 pub use core::array;
259 pub use core::{concat, stringify};
260}