Skip to main content

lite_strtab/types/
string_index.rs

1//! Backing integer types for [`crate::StringId`].
2//!
3//! [`crate::StringId`] is the semantic handle used by the API, while
4//! [`StringIndex`] defines which integer types can store its raw value.
5//! Smaller types reduce memory per ID; larger types increase maximum string
6//! count.
7//!
8//! Default [`u16`] supports up to 65_536 strings per table.
9
10/// Contract for integer types used by [`crate::StringId`].
11///
12/// [`Self::try_from_usize`] is used at build and validation boundaries where
13/// counts are computed as [`usize`]. [`Self::to_usize`] is used on lookup paths
14/// for infallible indexing.
15///
16/// # Implementing this trait
17///
18/// This trait is already implemented for primitive unsigned integers (`u8`, `u16`, `u32`,
19/// `u64`, `usize`). To implement it for custom wrapper types, use the
20/// [`impl_string_index`](crate::impl_string_index) macro:
21///
22/// ```
23/// use lite_strtab::impl_string_index;
24///
25/// #[derive(Clone, Copy)]
26/// #[repr(transparent)]
27/// struct ProviderIdx(u16);
28///
29/// impl_string_index!(ProviderIdx: u16);
30/// ```
31pub trait StringIndex: Copy + Send + Sync + 'static {
32    /// Human-readable type name.
33    const TYPE_NAME: &'static str;
34
35    /// Converts a string index into this type.
36    fn try_from_usize(value: usize) -> Option<Self>;
37
38    /// Converts this index to [`usize`].
39    fn to_usize(self) -> usize;
40}
41
42/// Implements [`StringIndex`] for one or more types.
43///
44/// # Examples
45///
46/// For wrapper types with an inner integer type:
47///
48/// ```
49/// use lite_strtab::impl_string_index;
50///
51/// #[derive(Clone, Copy)]
52/// #[repr(transparent)]
53/// struct ProviderIdx(u16);
54///
55/// impl_string_index!(ProviderIdx: u16);
56/// ```
57#[macro_export]
58macro_rules! impl_string_index {
59    // Pattern for wrapper types: Type: InnerType
60    ($wrapper:ty: $inner:ty) => {
61        impl $crate::StringIndex for $wrapper {
62            const TYPE_NAME: &'static str = stringify!($wrapper);
63
64            #[inline]
65            fn try_from_usize(value: usize) -> Option<Self> {
66                <$inner as $crate::StringIndex>::try_from_usize(value).map(Self)
67            }
68
69            #[inline]
70            fn to_usize(self) -> usize {
71                <$inner as $crate::StringIndex>::to_usize(self.0)
72            }
73        }
74    };
75
76    // Pattern for multiple wrapper types
77    ($wrapper:ty: $inner:ty, $($rest:tt)*) => {
78        $crate::impl_string_index!($wrapper: $inner);
79        $crate::impl_string_index!($($rest)*);
80    };
81
82    // Pattern for primitive types
83    ($($ty:ty),+ $(,)?) => {
84        $(
85            impl $crate::StringIndex for $ty {
86                const TYPE_NAME: &'static str = stringify!($ty);
87
88                #[inline]
89                fn try_from_usize(value: usize) -> Option<Self> {
90                    <Self as core::convert::TryFrom<usize>>::try_from(value).ok()
91                }
92
93                #[inline]
94                fn to_usize(self) -> usize {
95                    self as usize
96                }
97            }
98        )+
99    };
100}
101
102#[cfg(target_pointer_width = "64")]
103crate::impl_string_index!(u8, u16, u32, u64, usize);
104
105#[cfg(target_pointer_width = "32")]
106crate::impl_string_index!(u8, u16, u32, usize);
107
108#[cfg(target_pointer_width = "16")]
109crate::impl_string_index!(u8, u16, usize);
110
111// Supported pointer widths for this crate.
112#[cfg(not(any(
113    target_pointer_width = "16",
114    target_pointer_width = "32",
115    target_pointer_width = "64"
116)))]
117compile_error!("lite-strtab requires a 16-bit, 32-bit, or 64-bit target");