1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
//! Interfaces and types to be used as symbols for the //! [`StringInterner`](`crate::StringInterner`). //! //! The [`StringInterner::get_or_intern`](`crate::StringInterner::get_or_intern`) //! method returns `Symbol` types that allow to look-up the original string //! using [`StringInterner::resolve`](`crate::StringInterner::resolve`). use core::num::{ NonZeroU16, NonZeroU32, NonZeroUsize, }; /// Types implementing this trait can be used as symbols for string interners. /// /// The [`StringInterner::get_or_intern`](`crate::StringInterner::get_or_intern`) /// method returns `Symbol` types that allow to look-up the original string /// using [`StringInterner::resolve`](`crate::StringInterner::resolve`). /// /// # Note /// /// Optimal symbols allow for efficient comparisons and have a small memory footprint. pub trait Symbol: Copy + Eq { /// Creates a symbol from a `usize`. /// /// Returns `None` if `index` is out of bounds for the symbol. fn try_from_usize(index: usize) -> Option<Self>; /// Returns the `usize` representation of `self`. fn to_usize(self) -> usize; } /// Creates the symbol `S` from the given `usize`. /// /// # Panics /// /// Panics if the conversion is invalid. pub(crate) fn expect_valid_symbol<S>(index: usize) -> S where S: Symbol, { S::try_from_usize(index).expect("encountered invalid symbol") } /// The symbol type that is used by default. pub type DefaultSymbol = SymbolU32; macro_rules! gen_symbol_for { ( $( #[$doc:meta] )* struct $name:ident($non_zero:ty; $base_ty:ty); ) => { $( #[$doc] )* #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $name { value: $non_zero, } impl Symbol for $name { #[inline] fn try_from_usize(index: usize) -> Option<Self> { if index < usize::MAX { return Some(Self { value: unsafe { <$non_zero>::new_unchecked(index as $base_ty + 1) }, }) } None } #[inline] fn to_usize(self) -> usize { self.value.get() as usize - 1 } } }; } gen_symbol_for!( /// Symbol that is 16-bit in size. /// /// Is space-optimized for used in `Option`. struct SymbolU16(NonZeroU16; u16); ); gen_symbol_for!( /// Symbol that is 32-bit in size. /// /// Is space-optimized for used in `Option`. struct SymbolU32(NonZeroU32; u32); ); gen_symbol_for!( /// Symbol that is the same size as a pointer (`usize`). /// /// Is space-optimized for used in `Option`. struct SymbolUsize(NonZeroUsize; usize); );