string_hash_interner/
symbol.rs1use core::num::{NonZeroU16, NonZeroU32, NonZeroUsize};
9
10pub trait Symbol: Copy + Eq {
20 fn try_from_usize(index: usize) -> Option<Self>;
24
25 fn to_usize(self) -> usize;
27}
28
29#[inline]
35pub(crate) fn expect_valid_symbol<S>(index: usize) -> S
36where
37 S: Symbol,
38{
39 S::try_from_usize(index).expect("encountered invalid symbol")
40}
41
42pub type DefaultSymbol = SymbolU32;
44
45impl Symbol for usize {
46 #[inline]
47 fn try_from_usize(index: usize) -> Option<Self> {
48 Some(index)
49 }
50
51 #[inline]
52 fn to_usize(self) -> usize {
53 self
54 }
55}
56
57macro_rules! gen_symbol_for {
58 (
59 $( #[$doc:meta] )*
60 struct $name:ident($non_zero:ty; $base_ty:ty);
61 ) => {
62 $( #[$doc] )*
63 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
64 pub struct $name {
65 pub(crate) value: $non_zero,
66 }
67
68 impl $name {
69 pub(crate) fn new(index: $base_ty) -> Option<Self> {
70 <$non_zero>::new((index).wrapping_add(1))
71 .map(|value| Self { value })
72 }
73 }
74
75 impl Symbol for $name {
76 #[inline]
77 fn try_from_usize(index: usize) -> Option<Self> {
78 <$base_ty>::try_from(index).ok().and_then(Self::new)
79 }
80
81 #[inline]
82 fn to_usize(self) -> usize {
83 self.value.get() as usize - 1
84 }
85 }
86 };
87}
88gen_symbol_for!(
89 struct SymbolU16(NonZeroU16; u16);
93);
94gen_symbol_for!(
95 struct SymbolU32(NonZeroU32; u32);
99);
100gen_symbol_for!(
101 struct SymbolUsize(NonZeroUsize; usize);
105);
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn same_size_as_u32() {
113 assert_eq!(size_of::<DefaultSymbol>(), size_of::<u32>());
114 }
115
116 #[test]
117 fn same_size_as_optional() {
118 assert_eq!(
119 size_of::<DefaultSymbol>(),
120 size_of::<Option<DefaultSymbol>>()
121 );
122 }
123
124 #[test]
125 fn try_from_usize_works() {
126 assert_eq!(
127 SymbolU16::try_from_usize(0),
128 Some(SymbolU16 {
129 value: NonZeroU16::new(1).unwrap()
130 })
131 );
132 assert_eq!(
133 SymbolU16::try_from_usize(u16::MAX as usize - 1),
134 Some(SymbolU16 {
135 value: NonZeroU16::new(u16::MAX).unwrap()
136 })
137 );
138 assert_eq!(SymbolU16::try_from_usize(u16::MAX as usize), None);
139 assert_eq!(SymbolU16::try_from_usize(u16::MAX as usize + 1), None);
140 assert_eq!(SymbolU16::try_from_usize(u16::MAX as usize + 123456), None);
141 assert_eq!(SymbolU16::try_from_usize(usize::MAX), None);
142 assert_eq!(SymbolU16::try_from_usize(usize::MAX - 1), None);
143 assert_eq!(SymbolU16::try_from_usize(usize::MAX - 123456), None);
144 }
145
146 macro_rules! gen_test_for {
147 ( $test_name:ident: struct $name:ident($non_zero:ty; $base_ty:ty); ) => {
148 #[test]
149 fn $test_name() {
150 for val in 0..10 {
151 assert_eq!(
152 <$name>::try_from_usize(val),
153 Some($name {
154 value: <$non_zero>::new(val as $base_ty + 1).unwrap()
155 })
156 );
157 }
158 assert_eq!(
159 <$name>::try_from_usize(<$base_ty>::MAX as usize - 1),
160 Some($name {
161 value: <$non_zero>::new(<$base_ty>::MAX).unwrap()
162 })
163 );
164 assert_eq!(<$name>::try_from_usize(<$base_ty>::MAX as usize), None);
165 assert_eq!(<$name>::try_from_usize(<usize>::MAX), None);
166 }
167 };
168 }
169 gen_test_for!(
170 try_from_usize_works_for_u16:
171 struct SymbolU16(NonZeroU16; u16);
172 );
173 gen_test_for!(
174 try_from_usize_works_for_u32:
175 struct SymbolU32(NonZeroU32; u32);
176 );
177 gen_test_for!(
178 try_from_usize_works_for_usize:
179 struct SymbolUsize(NonZeroUsize; usize);
180 );
181}