@@ -2632,6 +2632,19 @@ impl Symbol {
26322632 } )
26332633 }
26342634
2635+ /// Runs `f` with access to the symbol interner, so you can call
2636+ /// `interner.get_str(sym)` instead of `sym.as_str()`.
2637+ ///
2638+ /// This is for performance: it lets you get the contents of multiple
2639+ /// symbols with a single TLS lookup and interner lock operation, instead
2640+ /// of doing those operations once per symbol.
2641+ pub fn with_interner < R > ( f : impl FnOnce ( & InternerInner ) -> R ) -> R {
2642+ with_session_globals ( |session_globals| {
2643+ let inner = session_globals. symbol_interner . 0 . lock ( ) ;
2644+ f ( & inner)
2645+ } )
2646+ }
2647+
26352648 pub fn as_u32 ( self ) -> u32 {
26362649 self . 0 . as_u32 ( )
26372650 }
@@ -2733,14 +2746,13 @@ impl<CTX> HashStable<CTX> for ByteSymbol {
27332746// string with identical contents (e.g. "foo" and b"foo") are both interned,
27342747// only one copy will be stored and the resulting `Symbol` and `ByteSymbol`
27352748// will have the same index.
2749+ //
2750+ // There must only be one of these, otherwise its easy to mix up symbols
2751+ // between interners.
27362752pub ( crate ) struct Interner ( Lock < InternerInner > ) ;
27372753
27382754// The `&'static [u8]`s in this type actually point into the arena.
2739- //
2740- // This type is private to prevent accidentally constructing more than one
2741- // `Interner` on the same thread, which makes it easy to mix up `Symbol`s
2742- // between `Interner`s.
2743- struct InternerInner {
2755+ pub struct InternerInner {
27442756 arena : DroplessArena ,
27452757 byte_strs : FxIndexSet < & ' static [ u8 ] > ,
27462758}
@@ -2794,21 +2806,37 @@ impl Interner {
27942806 /// Get the symbol as a string.
27952807 ///
27962808 /// [`Symbol::as_str()`] should be used in preference to this function.
2809+ /// (Or [`Symbol::with_interner()`] + [`InternerInner::get_str()`]).
27972810 fn get_str ( & self , symbol : Symbol ) -> & str {
2798- let byte_str = self . get_inner ( symbol. 0 . as_usize ( ) ) ;
2811+ let inner = self . 0 . lock ( ) ;
2812+ let byte_str = inner. byte_strs . get_index ( symbol. 0 . as_usize ( ) ) . unwrap ( ) ;
27992813 // SAFETY: known to be a UTF8 string because it's a `Symbol`.
28002814 unsafe { str:: from_utf8_unchecked ( byte_str) }
28012815 }
28022816
28032817 /// Get the symbol as a string.
28042818 ///
28052819 /// [`ByteSymbol::as_byte_str()`] should be used in preference to this function.
2820+ /// (Or [`Symbol::with_interner()`] + [`InternerInner::get_byte_str()`]).
28062821 fn get_byte_str ( & self , symbol : ByteSymbol ) -> & [ u8 ] {
2807- self . get_inner ( symbol. 0 . as_usize ( ) )
2822+ let inner = self . 0 . lock ( ) ;
2823+ inner. byte_strs . get_index ( symbol. 0 . as_usize ( ) ) . unwrap ( )
28082824 }
2825+ }
28092826
2810- fn get_inner ( & self , index : usize ) -> & [ u8 ] {
2811- self . 0 . lock ( ) . byte_strs . get_index ( index) . unwrap ( )
2827+ impl InternerInner {
2828+ /// Get the symbol as a string. Used with `with_interner`.
2829+ #[ inline]
2830+ pub fn get_str ( & self , symbol : Symbol ) -> & str {
2831+ let byte_str = self . byte_strs . get_index ( symbol. 0 . as_usize ( ) ) . unwrap ( ) ;
2832+ // SAFETY: known to be a UTF8 string because it's a `Symbol`.
2833+ unsafe { str:: from_utf8_unchecked ( byte_str) }
2834+ }
2835+
2836+ /// Get the symbol as a string. Used with `with_interner`.
2837+ #[ inline]
2838+ pub fn get_byte_str ( & self , symbol : ByteSymbol ) -> & [ u8 ] {
2839+ self . byte_strs . get_index ( symbol. 0 . as_usize ( ) ) . unwrap ( )
28122840 }
28132841}
28142842
0 commit comments