tstr 0.3.1

type-level strings on stable
Documentation
/// The type of a type-level string, always a [`TStr`].
///
/// # Arguments
///
/// You can use any of these as arguments:
///
/// - String literals (eg: `TS!("hello")`, `TS!(r#"world"#)`)
///
/// - Integers (eg: `TS!(0)`, `TS!(100)`):
/// converting the integer to decimal, then stringifying it.
///
/// - Single identifiers (eg: `TS!(foo)`, `TS!(bar)`): stringifying the identifier.
///
/// - `concat!(...)`-like syntax: concatenates its arguments,
/// accepting the same arguments as this macro.
///
/// - `stringify!(...)`-like syntax: stringifies its arguments.
/// Be careful using strings that stringify multiple tokens,
/// because the spacing around tokens isn't guaranteed.
///
/// # Examples
///
/// ### ToVariant
///
/// This example demonstrates how you can use type-level strings to create a
/// `GetVariant` trait which gets the data in a variant if the enum is that variant.
///
/// ```rust
/// use tstr::{TS, ts};
///
/// fn main(){
///     let foo = Enum::Foo(3, 5);
///     let bar = Enum::Bar("hello".to_string());
///     
///     assert_eq!(foo.to_variant(ts!(Foo)), Some((3, 5)));
///     assert_eq!(foo.to_variant(ts!(Bar)), None);
///     
///     assert_eq!(bar.to_variant(ts!(Foo)), None);
///     assert_eq!(bar.to_variant(ts!(Bar)), Some("hello".to_string()));
/// }
///
/// trait ToVariant<V> {
///     type Output;
///     
///     fn to_variant(&self, variant: V) -> Option<Self::Output>;
/// }
///
/// enum Enum {
///     Foo(u32, u64),
///     Bar(String),
/// }
///
/// impl ToVariant<TS!(Foo)> for Enum {
///     type Output = (u32, u64);
///     
///     fn to_variant(&self, variant: TS!(Foo)) -> Option<Self::Output> {
///         match self {
///             Self::Foo(l, r) => Some((*l, *r)),
///             _ => None,
///         }
///     }
/// }
///
/// impl ToVariant<TS!(Bar)> for Enum {
///     type Output = String;
///     
///     fn to_variant(&self, variant: TS!(Bar)) -> Option<Self::Output> {
///         match self {
///             Self::Bar(s) => Some(s.clone()),
///             _ => None,
///         }
///     }
/// }
///
///
/// ```
///
/// ### Equivalences
///
/// This example demonstrates which invocations of `TS` produce the same type.
///
/// ```rust
/// use tstr::TS;
///
/// type Hello1 = TS!("hello");
/// type Hello2 = TS!(hello); // This is equivalent to `TS!("hello")`
///
/// type HundredA = TS!("100");
/// type HundredB = TS!(100);   // equivalent to `TS!("100")`
/// type HundredC = TS!(0x64);  // equivalent to `TS!("100")`
/// type HundredD = TS!(0b1100100);  // equivalent to `TS!("100")`
///
/// // Equivalent to TS!("foo4bar200")
/// type Conc = TS!(concat!(foo, 0b100, "bar", 200));
///
/// ```
///
/// [`TStr`]: ./struct.TStr.html
#[macro_export]
macro_rules! TS {
    ("") => { $crate::__p::__Empty };
    (($expr:expr $(,)?)) => {
        $crate::__ts_impl!(($crate) $expr)
    };
    ($expr:expr $(,)? ) => {
        $crate::__ts_impl!(($crate) $expr)
    };
}

/// Constructs a type-level string ([`TStr`]) value.
///
/// # Arguments
///
/// This takes the same arguments as the [`tstr::TS`] macro.
///
/// # Examples
///
/// ### Indexing
///
/// ```rust
/// use tstr::{TS, ts};
///
/// # fn main() {
/// let this = Foo { bar: 3, baz: 'X', qux: "8" };
///
/// assert_eq!(this[ts!(bar)], 3);
/// assert_eq!(this[ts!(baz)], 'X');
/// assert_eq!(this[ts!(qux)], "8");
/// # }
///
/// #[derive(Debug)]
/// pub struct Foo {
///     bar: u32,
///     baz: char,
///     qux: &'static str,
/// }
///
/// impl_field_index!{ bar: u32 }
/// impl_field_index!{ baz: char }
/// impl_field_index!{ qux: &'static str }
///
/// macro_rules! impl_field_index {
///     ($field_name:ident: $field_type:ty) => {
///         impl std::ops::Index<TS!($field_name)> for Foo {
///             type Output = $field_type;
///
///             fn index(&self, _: TS!($field_name)) -> &$field_type {
///                 &self.$field_name
///             }
///         }
///
///         impl std::ops::IndexMut<TS!($field_name)> for Foo {
///             fn index_mut(&mut self, _: TS!($field_name)) -> &mut $field_type {
///                 &mut self.$field_name
///             }
///         }
///     }
/// } use impl_field_index;
///
/// ```
/// ### Equivalences
///
/// This example demonstrates which invocations of `ts` produce the same values.
///
/// ```rust
/// use tstr::ts;
///
/// let hello1 = ts!("hello");
/// let hello2 = ts!(hello); // This is equivalent to `ts!("hello")`
///
/// let hundreda = ts!("100");
/// let hundredb = ts!(100);   // equivalent to `ts!("100")`
/// let hundredc = ts!(0x64);  // equivalent to `ts!("100")`
/// let hundredd = ts!(0b1100100);  // equivalent to `ts!("100")`
///
/// // Equivalent to ts!("foo4bar200")
/// let conc = ts!(concat!(foo, 0b100, "bar", 200));
/// # const _: tstr::TS!("foo4bar200") = ts!(concat!(foo, 0b100, "bar", 200));
/// ```
///
///
/// [`TStr`]: ./struct.TStr.html
/// [`tstr::TS`]: ./macro.TS.html#arguments
#[macro_export]
macro_rules! ts {
    ($($expr:tt)*) => {
        <$crate::TS!($($expr)*) as $crate::IsTStr>::VAL
    };
}

/// Declares `const` and `type` aliases for [type-level strings (`TStr`)](crate::TStr).
///
/// # String Arguments
///
/// You can alias a type-level string in these ways:
///
/// ```rust
/// tstr::alias!{
///     // Aliases the "bar" type-level string as both a const and a type, named Bar.
///     // (both the const and type are private to this module)
///     Bar = bar;
///
///     // Aliases the "0" type-level string.
///     // (both the const and type are private to this crate)
///     pub(crate) N0 = 0;
///
///     // Aliases the "foo" type-level string,
///     // (both the const and type are public)
///     pub Tup = "foo";
/// }
/// ```
///
/// Attributes on each alias (including documentation) are copied to
/// the generated constant and type.
///
/// # Examples
///
/// ### Indexing
///
/// ```rust
/// use std::ops::Index;
///
///
/// let this = Foo { bar: 3, baz: 'X', qux: "8" };
/// assert_eq!(get_bar_baz(&this), (3, 'X'));
///
/// let other = Bar { bar: 13, baz: false, qux: Some('C') };
/// assert_eq!(get_bar_baz(&other), (13, false));
///
///
/// tstr::alias!{
///     // Declares both an NBar type alias and an NBar constant of the `TStr` for "bar".
///     pub NBar = bar;
///
///     // Declares both an NBaz type alias and an NBaz constant of the `TStr` for "baz".
///     pub NBaz = "baz";
///
///     // Declares both an NQux type alias and an NQux constant of the `TStr` for "qux".
///     pub NQux = "qux";
/// }
///
///
/// type IndexOut<T, N> = <T as Index<N>>::Output;
///
/// fn get_bar_baz<T>(this: &T) -> (IndexOut<T, NBar>, IndexOut<T, NBaz>)
/// where
///     T: Index<NBar, Output: Copy> + Index<NBaz, Output: Copy>,
/// {
///     (this[NBar], this[NBaz])
/// }
///
///
/// #[derive(Debug)]
/// pub struct Foo {
///     bar: u32,
///     baz: char,
///     qux: &'static str,
/// }
///
/// impl_field_index!{ Foo,bar[NBar]: u32 }
/// impl_field_index!{ Foo,baz[NBaz]: char }
/// impl_field_index!{ Foo,qux[NQux]: &'static str }
///
///
/// #[derive(Debug)]
/// pub struct Bar {
///     bar: u32,
///     baz: bool,
///     qux: Option<char>,
/// }
///
/// impl_field_index!{ Bar,bar[NBar]: u32 }
/// impl_field_index!{ Bar,baz[NBaz]: bool }
/// impl_field_index!{ Bar,qux[NQux]: Option<char> }
///
/// macro_rules! impl_field_index {
///     ($Self:ty, $field_name:ident [$field_tstr:ident]: $field_type:ty) => {
///         impl std::ops::Index<$field_tstr> for $Self {
///             type Output = $field_type;
///
///             fn index(&self, _: $field_tstr) -> &$field_type {
///                 &self.$field_name
///             }
///         }
///
///         impl std::ops::IndexMut<$field_tstr> for $Self {
///             fn index_mut(&mut self, _: $field_tstr) -> &mut $field_type {
///                 &mut self.$field_name
///             }
///         }
///     }
/// } use impl_field_index;
///
/// ```
///
#[macro_export]
macro_rules! alias {
    (
        $(
            $(#[$attr:meta])*
            $vis:vis $name:ident = $expr:expr
        );*
        $(;)?
    ) => (
        $(
            $(#[$attr])*
            #[allow(broken_intra_doc_links)]
            #[allow(non_camel_case_types)]
            #[doc = $crate::__p::concat!(
                "An alias for `", $crate::__p::stringify!($expr), "` as a type level string.\n\n",
                "Generated by the [`::tstr::alias`] macro."
            )]
            $vis type $name = $crate::TS!($expr);

            $(#[$attr])*
            #[allow(non_upper_case_globals, broken_intra_doc_links)]
            #[doc = $crate::__p::concat!(
                "An alias for `", $crate::__p::stringify!($expr), "` as a type level string.\n\n",
                "Generated by the [`::tstr::alias`] macro."
            )]
            $vis const $name: $name = <$name as $crate::IsTStr>::VAL;
        )*
    );
}

#[doc(hidden)]
pub trait __PickFirst<B: ?Sized> {
    type First: ?Sized;
}

impl<A: ?Sized, B: ?Sized> __PickFirst<B> for A {
    type First = A;
}

// used by erroring macros to emit both a compile_error!() and a TStr type.
#[doc(hidden)]
pub type __IgnoreArgReturnEmpty<A> = <TS!("") as __PickFirst<A>>::First;