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");