1 //! An "interner" is a data structure that associates values with usize tags and
2 //! allows bidirectional lookup; i.e., given a value, one can easily find the
3 //! type, and vice versa.
5 use arena
::DroplessArena
;
6 use rustc_data_structures
::fx
::FxHashMap
;
7 use rustc_data_structures
::indexed_vec
::Idx
;
8 use rustc_data_structures
::newtype_index
;
9 use rustc_macros
::symbols
;
10 use serialize
::{Decodable, Decoder, Encodable, Encoder}
;
12 use std
::cmp
::{PartialEq, Ordering, PartialOrd, Ord}
;
14 use std
::hash
::{Hash, Hasher}
;
17 use crate::hygiene
::SyntaxContext
;
18 use crate::{Span, DUMMY_SP, GLOBALS}
;
21 // After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
22 // this should be rarely necessary though if the keywords are kept in alphabetic order.
24 // Special reserved identifiers used internally for elided lifetimes,
25 // unnamed method parameters, crate root module, error recovery etc.
28 DollarCrate
: "$crate",
31 // Keywords that are used in stable Rust.
68 // Keywords that are used in unstable Rust or reserved for future use.
82 // Edition-specific keywords that are used in stable Rust.
83 Dyn
: "dyn", // >= 2018 Edition only
85 // Edition-specific keywords that are used in unstable Rust or reserved for future use.
86 Async
: "async", // >= 2018 Edition only
87 Await
: "await", // >= 2018 Edition only
88 Try
: "try", // >= 2018 Edition only
90 // Special lifetime names
91 UnderscoreLifetime
: "'_",
92 StaticLifetime
: "'static",
94 // Weak keywords, have special meaning only in specific contexts.
98 Existential
: "existential",
102 // Symbols that can be referred to with syntax_pos::sym::*. The symbol is
103 // the stringified identifier unless otherwise specified (e.g.
104 // `proc_dash_macro` represents "proc-macro").
106 // As well as the symbols listed, there are symbols for the the strings
107 // "0", "1", ..., "9", which are accessible via `sym::integer`.
109 aarch64_target_feature
,
112 abi_msp430_interrupt
,
120 advanced_slice_patterns
,
132 allow_internal_unsafe
,
133 allow_internal_unstable
,
134 allow_internal_unstable_backcompat_hack
,
138 arbitrary_enum_discriminant
,
139 arbitrary_self_types
,
145 associated_type_bounds
,
146 associated_type_defaults
,
152 augmented_assignments
,
153 automatically_derived
,
154 avx512_target_feature
,
159 bind_by_move_pattern_guards
,
162 borrowck_graphviz_postflow
,
163 borrowck_graphviz_preflow
,
166 braced_empty_structs
,
173 cfg_target_has_atomic
,
174 cfg_target_thread_local
,
181 closure_to_fn_coercion
,
183 cmpxchg16b_target_feature
,
188 conservative_impl_trait
,
190 const_compare_raw_pointers
,
199 const_raw_ptr_to_usize_cast
,
212 crate_visibility_modifier
,
215 custom_inner_attributes
,
216 custom_test_frameworks
,
220 default_lib_allocator
,
221 default_type_parameter_fallback
,
235 document_private_items
,
236 dotdoteq_in_patterns
,
237 dotdot_in_tuple_patterns
,
238 double_braced_crate
: "{{crate}}",
239 double_braced_impl
: "{{impl}}",
240 double_braced_misc
: "{{misc}}",
241 double_braced_closure
: "{{closure}}",
242 double_braced_constructor
: "{{constructor}}",
243 double_braced_constant
: "{{constant}}",
244 double_braced_opaque
: "{{opaque}}",
246 dropck_parametricity
,
258 exclusive_range_pattern
,
259 exhaustive_integer_patterns
,
265 extern_absolute_paths
,
267 extern_crate_item_prelude
,
278 field_init_shorthand
,
300 generic_associated_types
,
309 hexagon_target_feature
,
311 homogeneous_aggregate
,
325 if_while_or_patterns
,
327 impl_header_lifetime_elision
,
328 impl_trait_in_bindings
,
334 inclusive_range_syntax
,
335 infer_outlives_requirements
,
336 infer_static_outlives_requirements
,
343 irrefutable_let_patterns
,
346 issue_5723_bootstrap
,
347 issue_tracker_base_url
,
366 link_llvm_intrinsics
,
374 macro_at_most_once_rep
,
377 macro_lifetime_matcher
,
378 macro_literal_matcher
,
389 match_beginning_vert
,
390 match_default_bindings
,
401 movbe_target_feature
,
435 omit_gdb_pretty_printer_section
,
442 optin_builtin_traits
,
450 overlapping_marker_traits
,
455 panic_implementation
,
474 poll_with_tls_context
,
475 powerpc_target_feature
,
476 precise_pointer_size_matching
,
480 proc_dash_macro
: "proc-macro",
482 proc_macro_attribute
,
489 proc_macro_non_items
,
490 proc_macro_path_invoc
,
494 quad_precision_float
,
507 reexport_test_harness_main
,
517 re_rebalance_coherence
,
531 rustc_allocator_nounwind
,
532 rustc_allow_const_fn_ptr
,
533 rustc_args_required_const
,
536 rustc_const_unstable
,
537 rustc_conversion_suggestion
,
538 rustc_copy_clone_marker
,
541 rustc_diagnostic_macros
,
543 rustc_doc_only_macro
,
545 rustc_dump_env_program_clauses
,
546 rustc_dump_program_clauses
,
547 rustc_dump_user_substs
,
549 rustc_expected_cgu_reuse
,
550 rustc_if_this_changed
,
551 rustc_inherit_overflow_checks
,
553 rustc_layout_scalar_valid_range_end
,
554 rustc_layout_scalar_valid_range_start
,
556 rustc_nonnull_optimization_guaranteed
,
557 rustc_object_lifetime_default
,
558 rustc_on_unimplemented
,
561 rustc_partition_codegened
,
562 rustc_partition_reused
,
564 rustc_peek_definite_init
,
565 rustc_peek_maybe_init
,
566 rustc_peek_maybe_uninit
,
568 rustc_proc_macro_decls
,
572 rustc_std_internal_symbol
,
576 rustc_then_this_would_need
,
577 rustc_transparent_macro
,
581 rust_eh_unwind_resume
,
583 __rust_unstable_column
,
584 rvalue_static_promotion
,
601 sse4a_target_feature
,
612 stmt_expr_attributes
,
614 struct_field_attributes
,
626 termination_trait_test
,
629 test_accepted_feature
,
631 test_removed_feature
,
653 type_alias_enum_variants
,
663 underscore_const_names
,
665 underscore_lifetimes
,
667 universal_impl_trait
,
670 unrestricted_attribute_tokens
,
671 unsafe_destructor_blind_to_params
,
674 unsized_tuple_coercion
,
689 visible_private_types
,
692 warn_directory_ownership
,
702 #[derive(Copy, Clone, Eq)]
710 /// Constructs a new identifier from a symbol and a span.
711 pub const fn new(name
: Symbol
, span
: Span
) -> Ident
{
715 /// Constructs a new identifier with an empty syntax context.
717 pub const fn with_empty_ctxt(name
: Symbol
) -> Ident
{
718 Ident
::new(name
, DUMMY_SP
)
722 pub fn invalid() -> Ident
{
723 Ident
::with_empty_ctxt(kw
::Invalid
)
726 /// Maps an interned string to an identifier with an empty syntax context.
727 pub fn from_interned_str(string
: InternedString
) -> Ident
{
728 Ident
::with_empty_ctxt(string
.as_symbol())
731 /// Maps a string to an identifier with an empty span.
732 pub fn from_str(string
: &str) -> Ident
{
733 Ident
::with_empty_ctxt(Symbol
::intern(string
))
736 /// Maps a string and a span to an identifier.
737 pub fn from_str_and_span(string
: &str, span
: Span
) -> Ident
{
738 Ident
::new(Symbol
::intern(string
), span
)
741 /// Replaces `lo` and `hi` with those from `span`, but keep hygiene context.
742 pub fn with_span_pos(self, span
: Span
) -> Ident
{
743 Ident
::new(self.name
, span
.with_ctxt(self.span
.ctxt()))
746 pub fn without_first_quote(self) -> Ident
{
747 Ident
::new(Symbol
::intern(self.as_str().trim_start_matches('
\''
)), self.span
)
750 /// "Normalize" ident for use in comparisons using "item hygiene".
751 /// Identifiers with same string value become same if they came from the same "modern" macro
752 /// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from
753 /// different "modern" macros.
754 /// Technically, this operation strips all non-opaque marks from ident's syntactic context.
755 pub fn modern(self) -> Ident
{
756 Ident
::new(self.name
, self.span
.modern())
759 /// "Normalize" ident for use in comparisons using "local variable hygiene".
760 /// Identifiers with same string value become same if they came from the same non-transparent
761 /// macro (e.g., `macro` or `macro_rules!` items) and stay different if they came from different
762 /// non-transparent macros.
763 /// Technically, this operation strips all transparent marks from ident's syntactic context.
764 pub fn modern_and_legacy(self) -> Ident
{
765 Ident
::new(self.name
, self.span
.modern_and_legacy())
768 /// Transforms an identifier into one with the same name, but gensymed.
769 pub fn gensym(self) -> Ident
{
770 let name
= with_interner(|interner
| interner
.gensymed(self.name
));
771 Ident
::new(name
, self.span
)
774 /// Transforms an underscore identifier into one with the same name, but
775 /// gensymed. Leaves non-underscore identifiers unchanged.
776 pub fn gensym_if_underscore(self) -> Ident
{
777 if self.name
== kw
::Underscore { self.gensym() }
else { self }
780 // WARNING: this function is deprecated and will be removed in the future.
781 pub fn is_gensymed(self) -> bool
{
782 with_interner(|interner
| interner
.is_gensymed(self.name
))
785 pub fn as_str(self) -> LocalInternedString
{
789 pub fn as_interned_str(self) -> InternedString
{
790 self.name
.as_interned_str()
794 impl PartialEq
for Ident
{
795 fn eq(&self, rhs
: &Self) -> bool
{
796 self.name
== rhs
.name
&& self.span
.ctxt() == rhs
.span
.ctxt()
800 impl Hash
for Ident
{
801 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
802 self.name
.hash(state
);
803 self.span
.ctxt().hash(state
);
807 impl fmt
::Debug
for Ident
{
808 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
809 write
!(f
, "{}{:?}", self.name
, self.span
.ctxt())
813 impl fmt
::Display
for Ident
{
814 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
815 fmt
::Display
::fmt(&self.name
, f
)
819 impl Encodable
for Ident
{
820 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
821 if self.span
.ctxt().modern() == SyntaxContext
::empty() {
822 s
.emit_str(&self.as_str())
823 } else { // FIXME(jseyfried): intercrate hygiene
824 let mut string
= "#".to_owned();
825 string
.push_str(&self.as_str());
831 impl Decodable
for Ident
{
832 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<Ident
, D
::Error
> {
833 let string
= d
.read_str()?
;
834 Ok(if !string
.starts_with('
#') {
835 Ident
::from_str(&string
)
836 } else { // FIXME(jseyfried): intercrate hygiene
837 Ident
::from_str(&string
[1..]).gensym()
842 /// A symbol is an interned or gensymed string. A gensym is a symbol that is
843 /// never equal to any other symbol.
845 /// Conceptually, a gensym can be thought of as a normal symbol with an
846 /// invisible unique suffix. Gensyms are useful when creating new identifiers
847 /// that must not match any existing identifiers, e.g. during macro expansion
848 /// and syntax desugaring. Because gensyms should always be identifiers, all
849 /// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
850 /// future the gensym-ness may be moved from `Symbol` to hygiene data.)
854 /// assert_eq!(Ident::from_str("x"), Ident::from_str("x"))
855 /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x"))
856 /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym())
858 /// Internally, a symbol is implemented as an index, and all operations
859 /// (including hashing, equality, and ordering) operate on that index. The use
860 /// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
861 /// because `newtype_index!` reserves the last 256 values for tagging purposes.
863 /// Note that `Symbol` cannot directly be a `newtype_index!` because it
864 /// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
865 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
866 pub struct Symbol(SymbolIndex
);
869 pub struct SymbolIndex { .. }
873 const fn new(n
: u32) -> Self {
874 Symbol(SymbolIndex
::from_u32_const(n
))
877 /// Maps a string to its interned representation.
878 pub fn intern(string
: &str) -> Self {
879 with_interner(|interner
| interner
.intern(string
))
882 pub fn as_str(self) -> LocalInternedString
{
883 with_interner(|interner
| unsafe {
884 LocalInternedString
{
885 string
: std
::mem
::transmute
::<&str, &str>(interner
.get(self))
890 pub fn as_interned_str(self) -> InternedString
{
891 with_interner(|interner
| InternedString
{
892 symbol
: interner
.interned(self)
896 pub fn as_u32(self) -> u32 {
901 impl fmt
::Debug
for Symbol
{
902 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
903 let is_gensymed
= with_interner(|interner
| interner
.is_gensymed(*self));
905 write
!(f
, "{}({:?})", self, self.0)
907 write
!(f
, "{}", self)
912 impl fmt
::Display
for Symbol
{
913 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
914 fmt
::Display
::fmt(&self.as_str(), f
)
918 impl Encodable
for Symbol
{
919 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
920 s
.emit_str(&self.as_str())
924 impl Decodable
for Symbol
{
925 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<Symbol
, D
::Error
> {
926 Ok(Symbol
::intern(&d
.read_str()?
))
930 // The `&'static str`s in this type actually point into the arena.
932 // Note that normal symbols are indexed upward from 0, and gensyms are indexed
933 // downward from SymbolIndex::MAX_AS_U32.
935 pub struct Interner
{
936 arena
: DroplessArena
,
937 names
: FxHashMap
<&'
static str, Symbol
>,
938 strings
: Vec
<&'
static str>,
939 gensyms
: Vec
<Symbol
>,
943 fn prefill(init
: &[&'
static str]) -> Self {
945 strings
: init
.into(),
946 names
: init
.iter().copied().zip((0..).map(Symbol
::new
)).collect(),
951 pub fn intern(&mut self, string
: &str) -> Symbol
{
952 if let Some(&name
) = self.names
.get(string
) {
956 let name
= Symbol
::new(self.strings
.len() as u32);
958 // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
960 let string
: &str = unsafe {
961 str::from_utf8_unchecked(self.arena
.alloc_slice(string
.as_bytes()))
963 // It is safe to extend the arena allocation to `'static` because we only access
964 // these while the arena is still alive.
965 let string
: &'
static str = unsafe {
966 &*(string
as *const str)
968 self.strings
.push(string
);
969 self.names
.insert(string
, name
);
973 fn interned(&self, symbol
: Symbol
) -> Symbol
{
974 if (symbol
.0.as_usize()) < self.strings
.len() {
977 self.gensyms
[(SymbolIndex
::MAX_AS_U32
- symbol
.0.as_u32()) as usize]
981 fn gensymed(&mut self, symbol
: Symbol
) -> Symbol
{
982 self.gensyms
.push(symbol
);
983 Symbol
::new(SymbolIndex
::MAX_AS_U32
- self.gensyms
.len() as u32 + 1)
986 fn is_gensymed(&mut self, symbol
: Symbol
) -> bool
{
987 symbol
.0.as_usize() >= self.strings
.len()
990 // Get the symbol as a string. `Symbol::as_str()` should be used in
991 // preference to this function.
992 pub fn get(&self, symbol
: Symbol
) -> &str {
993 match self.strings
.get(symbol
.0.as_usize()) {
994 Some(string
) => string
,
996 let symbol
= self.gensyms
[(SymbolIndex
::MAX_AS_U32
- symbol
.0.as_u32()) as usize];
997 self.strings
[symbol
.0.as_usize()]
1003 // This module has a very short name because it's used a lot.
1009 // This module has a very short name because it's used a lot.
1011 use std
::convert
::TryInto
;
1016 // Get the symbol for an integer. The first few non-negative integers each
1017 // have a static symbol and therefore are fast.
1018 pub fn integer
<N
: TryInto
<usize> + Copy
+ ToString
>(n
: N
) -> Symbol
{
1019 if let Result
::Ok(idx
) = n
.try_into() {
1020 if let Option
::Some(&sym
) = digits_array
.get(idx
) {
1024 Symbol
::intern(&n
.to_string())
1029 fn is_used_keyword_2018(self) -> bool
{
1033 fn is_unused_keyword_2018(self) -> bool
{
1034 self >= kw
::Async
&& self <= kw
::Try
1037 /// Used for sanity checking rustdoc keyword sections.
1038 pub fn is_doc_keyword(self) -> bool
{
1042 /// A keyword or reserved identifier that can be used as a path segment.
1043 pub fn is_path_segment_keyword(self) -> bool
{
1044 self == kw
::Super
||
1045 self == kw
::SelfLower
||
1046 self == kw
::SelfUpper
||
1047 self == kw
::Crate
||
1048 self == kw
::PathRoot
||
1049 self == kw
::DollarCrate
1052 /// This symbol can be a raw identifier.
1053 pub fn can_be_raw(self) -> bool
{
1054 self != kw
::Invalid
&& self != kw
::Underscore
&& !self.is_path_segment_keyword()
1059 // Returns `true` for reserved identifiers used internally for elided lifetimes,
1060 // unnamed method parameters, crate root module, error recovery etc.
1061 pub fn is_special(self) -> bool
{
1062 self.name
<= kw
::Underscore
1065 /// Returns `true` if the token is a keyword used in the language.
1066 pub fn is_used_keyword(self) -> bool
{
1067 // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
1068 self.name
>= kw
::As
&& self.name
<= kw
::While
||
1069 self.name
.is_used_keyword_2018() && self.span
.rust_2018()
1072 /// Returns `true` if the token is a keyword reserved for possible future use.
1073 pub fn is_unused_keyword(self) -> bool
{
1074 // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
1075 self.name
>= kw
::Abstract
&& self.name
<= kw
::Yield
||
1076 self.name
.is_unused_keyword_2018() && self.span
.rust_2018()
1079 /// Returns `true` if the token is either a special identifier or a keyword.
1080 pub fn is_reserved(self) -> bool
{
1081 self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
1084 /// A keyword or reserved identifier that can be used as a path segment.
1085 pub fn is_path_segment_keyword(self) -> bool
{
1086 self.name
.is_path_segment_keyword()
1089 /// We see this identifier in a normal identifier position, like variable name or a type.
1090 /// How was it written originally? Did it use the raw form? Let's try to guess.
1091 pub fn is_raw_guess(self) -> bool
{
1092 self.name
.can_be_raw() && self.is_reserved()
1096 // If an interner exists, return it. Otherwise, prepare a fresh one.
1098 fn with_interner
<T
, F
: FnOnce(&mut Interner
) -> T
>(f
: F
) -> T
{
1099 GLOBALS
.with(|globals
| f(&mut *globals
.symbol_interner
.lock()))
1102 /// An alternative to `Symbol` and `InternedString`, useful when the chars
1103 /// within the symbol need to be accessed. It is best used for temporary
1106 /// Because the interner outlives any thread which uses this type, we can
1107 /// safely treat `string` which points to interner data, as an immortal string,
1108 /// as long as this type never crosses between threads.
1110 // FIXME: ensure that the interner outlives any thread which uses
1111 // `LocalInternedString`, by creating a new thread right after constructing the
1113 #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
1114 pub struct LocalInternedString
{
1115 string
: &'
static str,
1118 impl LocalInternedString
{
1119 /// Maps a string to its interned representation.
1120 pub fn intern(string
: &str) -> Self {
1121 let string
= with_interner(|interner
| {
1122 let symbol
= interner
.intern(string
);
1123 interner
.strings
[symbol
.0.as_usize()]
1125 LocalInternedString
{
1126 string
: unsafe { std::mem::transmute::<&str, &str>(string) }
1130 pub fn as_interned_str(self) -> InternedString
{
1132 symbol
: Symbol
::intern(self.string
)
1137 pub fn get(&self) -> &str {
1138 // This returns a valid string since we ensure that `self` outlives the interner
1139 // by creating the interner on a thread which outlives threads which can access it.
1140 // This type cannot move to a thread which outlives the interner since it does
1141 // not implement Send.
1146 impl<U
: ?Sized
> std
::convert
::AsRef
<U
> for LocalInternedString
1148 str: std
::convert
::AsRef
<U
>
1151 fn as_ref(&self) -> &U
{
1152 self.string
.as_ref()
1156 impl<T
: std
::ops
::Deref
<Target
= str>> std
::cmp
::PartialEq
<T
> for LocalInternedString
{
1157 fn eq(&self, other
: &T
) -> bool
{
1158 self.string
== other
.deref()
1162 impl std
::cmp
::PartialEq
<LocalInternedString
> for str {
1163 fn eq(&self, other
: &LocalInternedString
) -> bool
{
1164 self == other
.string
1168 impl<'a
> std
::cmp
::PartialEq
<LocalInternedString
> for &'a
str {
1169 fn eq(&self, other
: &LocalInternedString
) -> bool
{
1170 *self == other
.string
1174 impl std
::cmp
::PartialEq
<LocalInternedString
> for String
{
1175 fn eq(&self, other
: &LocalInternedString
) -> bool
{
1176 self == other
.string
1180 impl<'a
> std
::cmp
::PartialEq
<LocalInternedString
> for &'a String
{
1181 fn eq(&self, other
: &LocalInternedString
) -> bool
{
1182 *self == other
.string
1186 impl !Send
for LocalInternedString {}
1187 impl !Sync
for LocalInternedString {}
1189 impl std
::ops
::Deref
for LocalInternedString
{
1192 fn deref(&self) -> &str { self.string }
1195 impl fmt
::Debug
for LocalInternedString
{
1196 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1197 fmt
::Debug
::fmt(self.string
, f
)
1201 impl fmt
::Display
for LocalInternedString
{
1202 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1203 fmt
::Display
::fmt(self.string
, f
)
1207 impl Decodable
for LocalInternedString
{
1208 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<LocalInternedString
, D
::Error
> {
1209 Ok(LocalInternedString
::intern(&d
.read_str()?
))
1213 impl Encodable
for LocalInternedString
{
1214 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
1215 s
.emit_str(self.string
)
1219 /// An alternative to `Symbol` that is focused on string contents. It has two
1220 /// main differences to `Symbol`.
1222 /// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
1223 /// string chars rather than the symbol integer. This is useful when hash
1224 /// stability is required across compile sessions, or a guaranteed sort
1225 /// ordering is required.
1227 /// Second, gensym-ness is irrelevant. E.g.:
1229 /// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
1230 /// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
1232 #[derive(Clone, Copy, PartialEq, Eq)]
1233 pub struct InternedString
{
1237 impl InternedString
{
1238 /// Maps a string to its interned representation.
1239 pub fn intern(string
: &str) -> Self {
1241 symbol
: Symbol
::intern(string
)
1245 pub fn with
<F
: FnOnce(&str) -> R
, R
>(self, f
: F
) -> R
{
1246 let str = with_interner(|interner
| {
1247 interner
.get(self.symbol
) as *const str
1249 // This is safe because the interner keeps string alive until it is dropped.
1250 // We can access it because we know the interner is still alive since we use a
1251 // scoped thread local to access it, and it was alive at the beginning of this scope
1255 fn with2
<F
: FnOnce(&str, &str) -> R
, R
>(self, other
: &InternedString
, f
: F
) -> R
{
1256 let (self_str
, other_str
) = with_interner(|interner
| {
1257 (interner
.get(self.symbol
) as *const str,
1258 interner
.get(other
.symbol
) as *const str)
1260 // This is safe for the same reason that `with` is safe.
1261 unsafe { f(&*self_str, &*other_str) }
1264 pub fn as_symbol(self) -> Symbol
{
1268 pub fn as_str(self) -> LocalInternedString
{
1269 self.symbol
.as_str()
1273 impl Hash
for InternedString
{
1274 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
1275 self.with(|str| str.hash(state
))
1279 impl PartialOrd
<InternedString
> for InternedString
{
1280 fn partial_cmp(&self, other
: &InternedString
) -> Option
<Ordering
> {
1281 if self.symbol
== other
.symbol
{
1282 return Some(Ordering
::Equal
);
1284 self.with2(other
, |self_str
, other_str
| self_str
.partial_cmp(other_str
))
1288 impl Ord
for InternedString
{
1289 fn cmp(&self, other
: &InternedString
) -> Ordering
{
1290 if self.symbol
== other
.symbol
{
1291 return Ordering
::Equal
;
1293 self.with2(other
, |self_str
, other_str
| self_str
.cmp(other_str
))
1297 impl fmt
::Debug
for InternedString
{
1298 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1299 self.with(|str| fmt
::Debug
::fmt(&str, f
))
1303 impl fmt
::Display
for InternedString
{
1304 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1305 self.with(|str| fmt
::Display
::fmt(&str, f
))
1309 impl Decodable
for InternedString
{
1310 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<InternedString
, D
::Error
> {
1311 Ok(InternedString
::intern(&d
.read_str()?
))
1315 impl Encodable
for InternedString
{
1316 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
1317 self.with(|string
| s
.emit_str(string
))
1328 fn interner_tests() {
1329 let mut i
: Interner
= Interner
::default();
1330 // first one is zero:
1331 assert_eq
!(i
.intern("dog"), Symbol
::new(0));
1332 // re-use gets the same entry:
1333 assert_eq
!(i
.intern("dog"), Symbol
::new(0));
1334 // different string gets a different #:
1335 assert_eq
!(i
.intern("cat"), Symbol
::new(1));
1336 assert_eq
!(i
.intern("cat"), Symbol
::new(1));
1337 // dog is still at zero
1338 assert_eq
!(i
.intern("dog"), Symbol
::new(0));
1339 let z
= i
.intern("zebra");
1340 assert_eq
!(i
.gensymed(z
), Symbol
::new(SymbolIndex
::MAX_AS_U32
));
1341 // gensym of same string gets new number:
1342 assert_eq
!(i
.gensymed(z
), Symbol
::new(SymbolIndex
::MAX_AS_U32
- 1));
1343 // gensym of *existing* string gets new number:
1344 let d
= i
.intern("dog");
1345 assert_eq
!(i
.gensymed(d
), Symbol
::new(SymbolIndex
::MAX_AS_U32
- 2));
1349 fn without_first_quote_test() {
1350 GLOBALS
.set(&Globals
::new(edition
::DEFAULT_EDITION
), || {
1351 let i
= Ident
::from_str("'break");
1352 assert_eq
!(i
.without_first_quote().name
, kw
::Break
);