tstr 0.3.1

type-level strings on stable
Documentation
//! An encoding of type-level strings, with the [`TStr`] type and related macros.
//!
//! This crate features all these on stable:
//! - a relatively readable default representation of type-level strings
//!   based on `char` const parameters.
//! - items for converting type-level strings to `&'static str` and `&'static [u8]`
//! - functions for comparing type-level strings to each other and `&str`
//! - macros for asserting the (in)equality of type-level strings to each other and `&str`
//!
//! All of the above functionality can be used in const contexts.
//!
//! # Examples
//!
//! ### Indexing
//!
//! This example demonstrates how you can use type-level strings,
//! and the [`Index`] trait, to access fields of generic types by name.
//!
//! ```rust
//! use std::ops::Index;
//!
//! use tstr::{TS, ts};
//!
//! fn main(){
//!     takes_person(&Person::new("Bob".into(), "Marley".into()));
//!
//!     takes_person(&OtherPerson::new("Bob", "Marley"));
//! }
//!
//! fn takes_person<P>(pers: &P)
//! where
//!     P: Index<TS!(name), Output = str> + Index<TS!(surname), Output = str>
//! {
//!     assert_eq!(&pers[ts!(name)], "Bob");
//!     assert_eq!(&pers[ts!(surname)], "Marley");
//! }
//!
//!
//! use person::Person;
//! mod person {
//!     use std::ops::Index;
//!
//!     use tstr::TS;
//!     
//!     pub struct Person {
//!         name: String,
//!         surname: String,
//!     }
//!     
//!     impl Person {
//!         pub fn new(name: String, surname: String) -> Self {
//!             Self{name, surname}
//!         }
//!     }
//!     
//!     impl Index<TS!(name)> for Person {
//!         type Output = str;
//!         
//!         fn index(&self, _: TS!(name)) -> &str {
//!             &self.name
//!         }
//!     }
//!    
//!     impl Index<TS!(surname)> for Person {
//!         type Output = str;
//!         
//!         fn index(&self, _: TS!(surname)) -> &str {
//!             &self.surname
//!         }
//!     }
//! }
//!
//! use other_person::OtherPerson;
//! mod other_person {
//!     use std::ops::Index;
//!
//!     use tstr::TS;
//!     
//!     pub struct OtherPerson {
//!         name: &'static str,
//!         surname: &'static str,
//!     }
//!     
//!     impl OtherPerson {
//!         pub fn new(name: &'static str, surname: &'static str) -> Self {
//!             Self{name, surname}
//!         }
//!     }
//!     
//!     impl Index<TS!(name)> for OtherPerson {
//!         type Output = str;
//!         
//!         fn index(&self, _: TS!(name)) -> &str {
//!             self.name
//!         }
//!     }
//!    
//!     impl Index<TS!(surname)> for OtherPerson {
//!         type Output = str;
//!         
//!         fn index(&self, _: TS!(surname)) -> &str {
//!             self.surname
//!         }
//!     }
//! }
//!
//! ```
//!
//! ### Type errors
//!
//! This example showcases what TStr looks like in simple type errors.
//!
//! ```rust,compile_fail
//! let _: tstr::TS!("Hello, world!") = ();
//! ```
//!
//! With no crate features enabled, the error message is this:
//! ```text
//! error[E0308]: mismatched types
//!  --> tstr/src/lib.rs:114:37
//!   |
//! 5 | let _: tstr::TS!("Hello, world!") = ();
//!   |        --------------------------   ^^ expected `TStr<___<..., 13>>`, found `()`
//!   |        |
//!   |        expected due to this
//!   |
//!   = note: expected struct `tstr::TStr<___<(tstr::__<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w'>, tstr::__<'o', 'r', 'l', 'd', '!'>, (), (), (), (), (), ()), 13>>`
//!           found unit type `()`
//! ```
//! As you can see, the string is represented as a collection of `char` const parameters.
//!
//! When the `"nightly_str_generics"` feature is enabled (which requires the nightly compiler),
//! the error message is this:
//! ```text
//! error[E0308]: mismatched types
//!  --> tstr/src/lib.rs:114:37
//!   |
//! 5 | let _: tstr::TS!("Hello, world!") = ();
//!   |        --------------------------   ^^ expected `TStr<___<"Hello, world!">>`, found `()`
//!   |        |
//!   |        expected due to this
//!   |
//!   = note: expected struct `tstr::TStr<___<"Hello, world!">>`
//!           found unit type `()`
//! ```
//!
//!
//!
//! # Macro expansion
//!
//! This library reserves the right to change how it represent type-level strings internally
//! in every single release, and cargo feature combination.
//!
//! This only affects you if you expand the code generated by macros from this crate,
//! and then use that expanded code instead of going through the macros.
//!
//! # Cargo features
//!
//! - `"const_panic"`(enabled by default):
//! Enables [`const_panic`] reexports, assertion macros,
//! and `const_panic::fmt::PanicFmt` impl for `TStr`.
//!
//! - `"use_syn"`(disabled by default):
//! Changes how literals passed to the macros of this crate are parsed to use the `syn` crate.
//! Use this if there is some literal that could not be
//! parsed but is a valid str/integer literal.
//!
//! - `"serde"`(disabled by default):
//! Enables serde dependency and implements `serde::{Serialize, Deserialize}` for `TStr`
//!
//! - `"str_generics"`(disabled by default):
//! Changes the representation of type-level strings to use a `&'static str` const parameter,
//! making for better compiler errors.
//! As of 2025-08-18, this feature can't be enabled, because it
//! requires `&'static str` to be stably usable as const parameters.
//! Consider using `"nightly_str_generics"` if this feature can't be used.
//!
//! - `"nightly_str_generics"`(disabled by default): Equivalent to the `"str_generics"` feature,
//! and enables the nightly compiler features to use `&'static str` const parameters.
//!
//! # No-std support
//!
//! This crate is unconditionally `#![no_std]`, and can be used anywhere that Rust can be.
//!
//! # Minimum Supported Rust Version
//!
//! This crate supports Rust versions back to Rust 1.88.0.
//!
//! [`TStr`]: crate::TStr
//! [`const_panic`]: const_panic
//! [`Index`]: core::ops::Index
//! [`tstr::utils`]: crate::utils
#![no_std]
#![cfg_attr(feature = "nightly_str_generics", feature(adt_const_params))]
#![cfg_attr(feature = "nightly_str_generics", feature(unsized_const_params))]
#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
#![cfg_attr(feature = "nightly_str_generics", allow(incomplete_features))]
//////////
// lints
//////////
#![allow(non_camel_case_types)]
#![forbid(unsafe_code)]

#[cfg(feature = "const_panic")]
mod assertions;

pub mod strlike;

mod macros;
mod private_macros;

mod tstr_fns;
mod tstr_trait;
mod tstr_type;

#[cfg(feature = "serde")]
mod tstr_serde_impls;

#[cfg(not(feature = "str_generics"))]
mod tstr_impl_with_chars;

#[cfg(not(feature = "str_generics"))]
pub(crate) use tstr_impl_with_chars::__TStrRepr;

#[cfg(feature = "str_generics")]
mod tstr_impl_with_str;

#[cfg(feature = "str_generics")]
pub(crate) use tstr_impl_with_str::__TStrRepr;

pub mod utils;

#[doc(hidden)]
extern crate self as tstr;

#[doc(hidden)]
pub use tstr_proc_macros::__ts_impl;

use crate::tstr_trait::__TStrArgBinary;

pub use crate::{
    tstr_fns::*,
    tstr_trait::{IsTStr, TStrArg},
    tstr_type::TStr,
};

pub use typewit;

#[doc(no_inline)]
#[cfg(feature = "const_panic")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_panic")))]
pub use const_panic::{self, unwrap_ok as unwrap};

include! {"./p.rs"}

#[doc(hidden)]
pub mod __p {
    pub use crate::__Empty;
    pub use crate::macros::__IgnoreArgReturnEmpty;

    #[cfg(feature = "const_panic")]
    pub use const_panic::concat_panic;

    pub use core::array;
    pub use core::{concat, stringify};
}