]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_pos/symbol.rs
Revert removed #![feature(nll)]
[rust.git] / src / libsyntax_pos / symbol.rs
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.
4
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 serialize::{Decodable, Decoder, Encodable, Encoder};
10
11 use std::fmt;
12 use std::str;
13 use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
14 use std::hash::{Hash, Hasher};
15
16 use crate::hygiene::SyntaxContext;
17 use crate::{Span, DUMMY_SP, GLOBALS};
18
19 #[derive(Copy, Clone, Eq)]
20 pub struct Ident {
21     pub name: Symbol,
22     pub span: Span,
23 }
24
25 impl Ident {
26     #[inline]
27     pub const fn new(name: Symbol, span: Span) -> Ident {
28         Ident { name, span }
29     }
30
31     #[inline]
32     pub const fn with_empty_ctxt(name: Symbol) -> Ident {
33         Ident::new(name, DUMMY_SP)
34     }
35
36     /// Maps an interned string to an identifier with an empty syntax context.
37     pub fn from_interned_str(string: InternedString) -> Ident {
38         Ident::with_empty_ctxt(string.as_symbol())
39     }
40
41     /// Maps a string to an identifier with an empty syntax context.
42     pub fn from_str(string: &str) -> Ident {
43         Ident::with_empty_ctxt(Symbol::intern(string))
44     }
45
46     /// Replace `lo` and `hi` with those from `span`, but keep hygiene context.
47     pub fn with_span_pos(self, span: Span) -> Ident {
48         Ident::new(self.name, span.with_ctxt(self.span.ctxt()))
49     }
50
51     pub fn without_first_quote(self) -> Ident {
52         Ident::new(Symbol::intern(self.as_str().trim_start_matches('\'')), self.span)
53     }
54
55     /// "Normalize" ident for use in comparisons using "item hygiene".
56     /// Identifiers with same string value become same if they came from the same "modern" macro
57     /// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from
58     /// different "modern" macros.
59     /// Technically, this operation strips all non-opaque marks from ident's syntactic context.
60     pub fn modern(self) -> Ident {
61         Ident::new(self.name, self.span.modern())
62     }
63
64     /// "Normalize" ident for use in comparisons using "local variable hygiene".
65     /// Identifiers with same string value become same if they came from the same non-transparent
66     /// macro (e.g., `macro` or `macro_rules!` items) and stay different if they came from different
67     /// non-transparent macros.
68     /// Technically, this operation strips all transparent marks from ident's syntactic context.
69     pub fn modern_and_legacy(self) -> Ident {
70         Ident::new(self.name, self.span.modern_and_legacy())
71     }
72
73     pub fn gensym(self) -> Ident {
74         Ident::new(self.name.gensymed(), self.span)
75     }
76
77     pub fn gensym_if_underscore(self) -> Ident {
78         if self.name == keywords::Underscore.name() { self.gensym() } else { self }
79     }
80
81     pub fn as_str(self) -> LocalInternedString {
82         self.name.as_str()
83     }
84
85     pub fn as_interned_str(self) -> InternedString {
86         self.name.as_interned_str()
87     }
88 }
89
90 impl PartialEq for Ident {
91     fn eq(&self, rhs: &Self) -> bool {
92         self.name == rhs.name && self.span.ctxt() == rhs.span.ctxt()
93     }
94 }
95
96 impl Hash for Ident {
97     fn hash<H: Hasher>(&self, state: &mut H) {
98         self.name.hash(state);
99         self.span.ctxt().hash(state);
100     }
101 }
102
103 impl fmt::Debug for Ident {
104     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105         write!(f, "{}{:?}", self.name, self.span.ctxt())
106     }
107 }
108
109 impl fmt::Display for Ident {
110     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111         fmt::Display::fmt(&self.name, f)
112     }
113 }
114
115 impl Encodable for Ident {
116     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
117         if self.span.ctxt().modern() == SyntaxContext::empty() {
118             s.emit_str(&self.as_str())
119         } else { // FIXME(jseyfried): intercrate hygiene
120             let mut string = "#".to_owned();
121             string.push_str(&self.as_str());
122             s.emit_str(&string)
123         }
124     }
125 }
126
127 impl Decodable for Ident {
128     fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
129         let string = d.read_str()?;
130         Ok(if !string.starts_with('#') {
131             Ident::from_str(&string)
132         } else { // FIXME(jseyfried): intercrate hygiene
133             Ident::with_empty_ctxt(Symbol::gensym(&string[1..]))
134         })
135     }
136 }
137
138 /// A symbol is an interned or gensymed string. The use of newtype_index! means
139 /// that Option<Symbol> only takes up 4 bytes, because newtype_index! reserves
140 /// the last 256 values for tagging purposes.
141 ///
142 /// Note that Symbol cannot be a newtype_index! directly because it implements
143 /// fmt::Debug, Encodable, and Decodable in special ways.
144 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
145 pub struct Symbol(SymbolIndex);
146
147 newtype_index! {
148     pub struct SymbolIndex { .. }
149 }
150
151 // The interner is pointed to by a thread local value which is only set on the main thread
152 // with parallelization is disabled. So we don't allow `Symbol` to transfer between threads
153 // to avoid panics and other errors, even though it would be memory safe to do so.
154 #[cfg(not(parallel_compiler))]
155 impl !Send for Symbol { }
156 #[cfg(not(parallel_compiler))]
157 impl !Sync for Symbol { }
158
159 impl Symbol {
160     const fn new(n: u32) -> Self {
161         Symbol(SymbolIndex::from_u32_const(n))
162     }
163
164     /// Maps a string to its interned representation.
165     pub fn intern(string: &str) -> Self {
166         with_interner(|interner| interner.intern(string))
167     }
168
169     pub fn interned(self) -> Self {
170         with_interner(|interner| interner.interned(self))
171     }
172
173     /// Gensyms a new usize, using the current interner.
174     pub fn gensym(string: &str) -> Self {
175         with_interner(|interner| interner.gensym(string))
176     }
177
178     pub fn gensymed(self) -> Self {
179         with_interner(|interner| interner.gensymed(self))
180     }
181
182     pub fn as_str(self) -> LocalInternedString {
183         with_interner(|interner| unsafe {
184             LocalInternedString {
185                 string: std::mem::transmute::<&str, &str>(interner.get(self))
186             }
187         })
188     }
189
190     pub fn as_interned_str(self) -> InternedString {
191         with_interner(|interner| InternedString {
192             symbol: interner.interned(self)
193         })
194     }
195
196     pub fn as_u32(self) -> u32 {
197         self.0.as_u32()
198     }
199 }
200
201 impl fmt::Debug for Symbol {
202     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203         let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
204         if is_gensymed {
205             write!(f, "{}({:?})", self, self.0)
206         } else {
207             write!(f, "{}", self)
208         }
209     }
210 }
211
212 impl fmt::Display for Symbol {
213     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214         fmt::Display::fmt(&self.as_str(), f)
215     }
216 }
217
218 impl Encodable for Symbol {
219     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
220         s.emit_str(&self.as_str())
221     }
222 }
223
224 impl Decodable for Symbol {
225     fn decode<D: Decoder>(d: &mut D) -> Result<Symbol, D::Error> {
226         Ok(Symbol::intern(&d.read_str()?))
227     }
228 }
229
230 impl<T: std::ops::Deref<Target=str>> PartialEq<T> for Symbol {
231     fn eq(&self, other: &T) -> bool {
232         self.as_str() == other.deref()
233     }
234 }
235
236 // The `&'static str`s in this type actually point into the arena.
237 //
238 // Note that normal symbols are indexed upward from 0, and gensyms are indexed
239 // downward from SymbolIndex::MAX_AS_U32.
240 #[derive(Default)]
241 pub struct Interner {
242     arena: DroplessArena,
243     names: FxHashMap<&'static str, Symbol>,
244     strings: Vec<&'static str>,
245     gensyms: Vec<Symbol>,
246 }
247
248 impl Interner {
249     fn prefill(init: &[&str]) -> Self {
250         let mut this = Interner::default();
251         for &string in init {
252             if string == "" {
253                 // We can't allocate empty strings in the arena, so handle this here.
254                 let name = Symbol::new(this.strings.len() as u32);
255                 this.names.insert("", name);
256                 this.strings.push("");
257             } else {
258                 this.intern(string);
259             }
260         }
261         this
262     }
263
264     pub fn intern(&mut self, string: &str) -> Symbol {
265         if let Some(&name) = self.names.get(string) {
266             return name;
267         }
268
269         let name = Symbol::new(self.strings.len() as u32);
270
271         // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
272         // UTF-8.
273         let string: &str = unsafe {
274             str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
275         };
276         // It is safe to extend the arena allocation to `'static` because we only access
277         // these while the arena is still alive.
278         let string: &'static str =  unsafe {
279             &*(string as *const str)
280         };
281         self.strings.push(string);
282         self.names.insert(string, name);
283         name
284     }
285
286     pub fn interned(&self, symbol: Symbol) -> Symbol {
287         if (symbol.0.as_usize()) < self.strings.len() {
288             symbol
289         } else {
290             self.interned(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize])
291         }
292     }
293
294     fn gensym(&mut self, string: &str) -> Symbol {
295         let symbol = self.intern(string);
296         self.gensymed(symbol)
297     }
298
299     fn gensymed(&mut self, symbol: Symbol) -> Symbol {
300         self.gensyms.push(symbol);
301         Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
302     }
303
304     fn is_gensymed(&mut self, symbol: Symbol) -> bool {
305         symbol.0.as_usize() >= self.strings.len()
306     }
307
308     pub fn get(&self, symbol: Symbol) -> &str {
309         match self.strings.get(symbol.0.as_usize()) {
310             Some(string) => string,
311             None => self.get(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]),
312         }
313     }
314 }
315
316 // In this macro, there is the requirement that the name (the number) must be monotonically
317 // increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
318 // except starting from the next number instead of zero.
319 macro_rules! declare_keywords {(
320     $( ($index: expr, $konst: ident, $string: expr) )*
321 ) => {
322     pub mod keywords {
323         use super::{Symbol, Ident};
324         #[derive(Clone, Copy, PartialEq, Eq)]
325         pub struct Keyword {
326             ident: Ident,
327         }
328         impl Keyword {
329             #[inline] pub fn ident(self) -> Ident { self.ident }
330             #[inline] pub fn name(self) -> Symbol { self.ident.name }
331         }
332         $(
333             #[allow(non_upper_case_globals)]
334             pub const $konst: Keyword = Keyword {
335                 ident: Ident::with_empty_ctxt(super::Symbol::new($index))
336             };
337         )*
338
339         impl std::str::FromStr for Keyword {
340             type Err = ();
341
342             fn from_str(s: &str) -> Result<Self, ()> {
343                 match s {
344                     $($string => Ok($konst),)*
345                     _ => Err(()),
346                 }
347             }
348         }
349     }
350
351     impl Interner {
352         pub fn fresh() -> Self {
353             Interner::prefill(&[$($string,)*])
354         }
355     }
356 }}
357
358 // N.B., leaving holes in the ident table is bad! a different ident will get
359 // interned with the id from the hole, but it will be between the min and max
360 // of the reserved words, and thus tagged as "reserved".
361 // After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
362 // this should be rarely necessary though if the keywords are kept in alphabetic order.
363 declare_keywords! {
364     // Special reserved identifiers used internally for elided lifetimes,
365     // unnamed method parameters, crate root module, error recovery etc.
366     (0,  Invalid,            "")
367     (1,  PathRoot,           "{{root}}")
368     (2,  DollarCrate,        "$crate")
369     (3,  Underscore,         "_")
370
371     // Keywords that are used in stable Rust.
372     (4,  As,                 "as")
373     (5,  Box,                "box")
374     (6,  Break,              "break")
375     (7,  Const,              "const")
376     (8,  Continue,           "continue")
377     (9,  Crate,              "crate")
378     (10, Else,               "else")
379     (11, Enum,               "enum")
380     (12, Extern,             "extern")
381     (13, False,              "false")
382     (14, Fn,                 "fn")
383     (15, For,                "for")
384     (16, If,                 "if")
385     (17, Impl,               "impl")
386     (18, In,                 "in")
387     (19, Let,                "let")
388     (20, Loop,               "loop")
389     (21, Match,              "match")
390     (22, Mod,                "mod")
391     (23, Move,               "move")
392     (24, Mut,                "mut")
393     (25, Pub,                "pub")
394     (26, Ref,                "ref")
395     (27, Return,             "return")
396     (28, SelfLower,          "self")
397     (29, SelfUpper,          "Self")
398     (30, Static,             "static")
399     (31, Struct,             "struct")
400     (32, Super,              "super")
401     (33, Trait,              "trait")
402     (34, True,               "true")
403     (35, Type,               "type")
404     (36, Unsafe,             "unsafe")
405     (37, Use,                "use")
406     (38, Where,              "where")
407     (39, While,              "while")
408
409     // Keywords that are used in unstable Rust or reserved for future use.
410     (40, Abstract,           "abstract")
411     (41, Become,             "become")
412     (42, Do,                 "do")
413     (43, Final,              "final")
414     (44, Macro,              "macro")
415     (45, Override,           "override")
416     (46, Priv,               "priv")
417     (47, Typeof,             "typeof")
418     (48, Unsized,            "unsized")
419     (49, Virtual,            "virtual")
420     (50, Yield,              "yield")
421
422     // Edition-specific keywords that are used in stable Rust.
423     (51, Dyn,                "dyn") // >= 2018 Edition only
424
425     // Edition-specific keywords that are used in unstable Rust or reserved for future use.
426     (52, Async,              "async") // >= 2018 Edition only
427     (53, Try,                "try") // >= 2018 Edition only
428
429     // Special lifetime names
430     (54, UnderscoreLifetime, "'_")
431     (55, StaticLifetime,     "'static")
432
433     // Weak keywords, have special meaning only in specific contexts.
434     (56, Auto,               "auto")
435     (57, Catch,              "catch")
436     (58, Default,            "default")
437     (59, Existential,        "existential")
438     (60, Union,              "union")
439 }
440
441 impl Symbol {
442     fn is_used_keyword_2018(self) -> bool {
443         self == keywords::Dyn.name()
444     }
445
446     fn is_unused_keyword_2018(self) -> bool {
447         self >= keywords::Async.name() && self <= keywords::Try.name()
448     }
449 }
450
451 impl Ident {
452     // Returns `true` for reserved identifiers used internally for elided lifetimes,
453     // unnamed method parameters, crate root module, error recovery etc.
454     pub fn is_special(self) -> bool {
455         self.name <= keywords::Underscore.name()
456     }
457
458     /// Returns `true` if the token is a keyword used in the language.
459     pub fn is_used_keyword(self) -> bool {
460         // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
461         self.name >= keywords::As.name() && self.name <= keywords::While.name() ||
462         self.name.is_used_keyword_2018() && self.span.rust_2018()
463     }
464
465     /// Returns `true` if the token is a keyword reserved for possible future use.
466     pub fn is_unused_keyword(self) -> bool {
467         // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
468         self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
469         self.name.is_unused_keyword_2018() && self.span.rust_2018()
470     }
471
472     /// Returns `true` if the token is either a special identifier or a keyword.
473     pub fn is_reserved(self) -> bool {
474         self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
475     }
476
477     /// A keyword or reserved identifier that can be used as a path segment.
478     pub fn is_path_segment_keyword(self) -> bool {
479         self.name == keywords::Super.name() ||
480         self.name == keywords::SelfLower.name() ||
481         self.name == keywords::SelfUpper.name() ||
482         self.name == keywords::Crate.name() ||
483         self.name == keywords::PathRoot.name() ||
484         self.name == keywords::DollarCrate.name()
485     }
486
487     // We see this identifier in a normal identifier position, like variable name or a type.
488     // How was it written originally? Did it use the raw form? Let's try to guess.
489     pub fn is_raw_guess(self) -> bool {
490         self.name != keywords::Invalid.name() && self.name != keywords::Underscore.name() &&
491         self.is_reserved() && !self.is_path_segment_keyword()
492     }
493 }
494
495 // If an interner exists, return it. Otherwise, prepare a fresh one.
496 #[inline]
497 fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
498     GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock()))
499 }
500
501 /// Represents a string stored in the interner. Because the interner outlives any thread
502 /// which uses this type, we can safely treat `string` which points to interner data,
503 /// as an immortal string, as long as this type never crosses between threads.
504 // FIXME: ensure that the interner outlives any thread which uses `LocalInternedString`,
505 // by creating a new thread right after constructing the interner.
506 #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
507 pub struct LocalInternedString {
508     string: &'static str,
509 }
510
511 impl LocalInternedString {
512     pub fn as_interned_str(self) -> InternedString {
513         InternedString {
514             symbol: Symbol::intern(self.string)
515         }
516     }
517
518     pub fn get(&self) -> &'static str {
519         self.string
520     }
521 }
522
523 impl<U: ?Sized> std::convert::AsRef<U> for LocalInternedString
524 where
525     str: std::convert::AsRef<U>
526 {
527     fn as_ref(&self) -> &U {
528         self.string.as_ref()
529     }
530 }
531
532 impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for LocalInternedString {
533     fn eq(&self, other: &T) -> bool {
534         self.string == other.deref()
535     }
536 }
537
538 impl std::cmp::PartialEq<LocalInternedString> for str {
539     fn eq(&self, other: &LocalInternedString) -> bool {
540         self == other.string
541     }
542 }
543
544 impl<'a> std::cmp::PartialEq<LocalInternedString> for &'a str {
545     fn eq(&self, other: &LocalInternedString) -> bool {
546         *self == other.string
547     }
548 }
549
550 impl std::cmp::PartialEq<LocalInternedString> for String {
551     fn eq(&self, other: &LocalInternedString) -> bool {
552         self == other.string
553     }
554 }
555
556 impl<'a> std::cmp::PartialEq<LocalInternedString> for &'a String {
557     fn eq(&self, other: &LocalInternedString) -> bool {
558         *self == other.string
559     }
560 }
561
562 impl !Send for LocalInternedString {}
563 impl !Sync for LocalInternedString {}
564
565 impl std::ops::Deref for LocalInternedString {
566     type Target = str;
567     fn deref(&self) -> &str { self.string }
568 }
569
570 impl fmt::Debug for LocalInternedString {
571     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
572         fmt::Debug::fmt(self.string, f)
573     }
574 }
575
576 impl fmt::Display for LocalInternedString {
577     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578         fmt::Display::fmt(self.string, f)
579     }
580 }
581
582 impl Decodable for LocalInternedString {
583     fn decode<D: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> {
584         Ok(Symbol::intern(&d.read_str()?).as_str())
585     }
586 }
587
588 impl Encodable for LocalInternedString {
589     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
590         s.emit_str(self.string)
591     }
592 }
593
594 /// Represents a string stored in the string interner.
595 #[derive(Clone, Copy, Eq)]
596 pub struct InternedString {
597     symbol: Symbol,
598 }
599
600 impl InternedString {
601     pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
602         let str = with_interner(|interner| {
603             interner.get(self.symbol) as *const str
604         });
605         // This is safe because the interner keeps string alive until it is dropped.
606         // We can access it because we know the interner is still alive since we use a
607         // scoped thread local to access it, and it was alive at the beginning of this scope
608         unsafe { f(&*str) }
609     }
610
611     pub fn as_symbol(self) -> Symbol {
612         self.symbol
613     }
614
615     pub fn as_str(self) -> LocalInternedString {
616         self.symbol.as_str()
617     }
618 }
619
620 impl Hash for InternedString {
621     fn hash<H: Hasher>(&self, state: &mut H) {
622         self.with(|str| str.hash(state))
623     }
624 }
625
626 impl PartialOrd<InternedString> for InternedString {
627     fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
628         if self.symbol == other.symbol {
629             return Some(Ordering::Equal);
630         }
631         self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
632     }
633 }
634
635 impl Ord for InternedString {
636     fn cmp(&self, other: &InternedString) -> Ordering {
637         if self.symbol == other.symbol {
638             return Ordering::Equal;
639         }
640         self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str)))
641     }
642 }
643
644 impl<T: std::ops::Deref<Target = str>> PartialEq<T> for InternedString {
645     fn eq(&self, other: &T) -> bool {
646         self.with(|string| string == other.deref())
647     }
648 }
649
650 impl PartialEq<InternedString> for InternedString {
651     fn eq(&self, other: &InternedString) -> bool {
652         self.symbol == other.symbol
653     }
654 }
655
656 impl PartialEq<InternedString> for str {
657     fn eq(&self, other: &InternedString) -> bool {
658         other.with(|string| self == string)
659     }
660 }
661
662 impl<'a> PartialEq<InternedString> for &'a str {
663     fn eq(&self, other: &InternedString) -> bool {
664         other.with(|string| *self == string)
665     }
666 }
667
668 impl PartialEq<InternedString> for String {
669     fn eq(&self, other: &InternedString) -> bool {
670         other.with(|string| self == string)
671     }
672 }
673
674 impl<'a> PartialEq<InternedString> for &'a String {
675     fn eq(&self, other: &InternedString) -> bool {
676         other.with(|string| *self == string)
677     }
678 }
679
680 impl std::convert::From<InternedString> for String {
681     fn from(val: InternedString) -> String {
682         val.as_symbol().to_string()
683     }
684 }
685
686 impl fmt::Debug for InternedString {
687     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688         self.with(|str| fmt::Debug::fmt(&str, f))
689     }
690 }
691
692 impl fmt::Display for InternedString {
693     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
694         self.with(|str| fmt::Display::fmt(&str, f))
695     }
696 }
697
698 impl Decodable for InternedString {
699     fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
700         Ok(Symbol::intern(&d.read_str()?).as_interned_str())
701     }
702 }
703
704 impl Encodable for InternedString {
705     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
706         self.with(|string| s.emit_str(string))
707     }
708 }
709
710 #[cfg(test)]
711 mod tests {
712     use super::*;
713     use crate::Globals;
714
715     #[test]
716     fn interner_tests() {
717         let mut i: Interner = Interner::default();
718         // first one is zero:
719         assert_eq!(i.intern("dog"), Symbol::new(0));
720         // re-use gets the same entry:
721         assert_eq!(i.intern("dog"), Symbol::new(0));
722         // different string gets a different #:
723         assert_eq!(i.intern("cat"), Symbol::new(1));
724         assert_eq!(i.intern("cat"), Symbol::new(1));
725         // dog is still at zero
726         assert_eq!(i.intern("dog"), Symbol::new(0));
727         assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32));
728         // gensym of same string gets new number:
729         assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
730         // gensym of *existing* string gets new number:
731         assert_eq!(i.gensym("dog"), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
732     }
733
734     #[test]
735     fn without_first_quote_test() {
736         GLOBALS.set(&Globals::new(), || {
737             let i = Ident::from_str("'break");
738             assert_eq!(i.without_first_quote().name, keywords::Break.name());
739         });
740     }
741 }