]> git.proxmox.com Git - rustc.git/blob - vendor/proc-macro2/src/fallback.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / vendor / proc-macro2 / src / fallback.rs
1 use crate::parse::{token_stream, Cursor};
2 use crate::{Delimiter, Spacing, TokenTree};
3 #[cfg(span_locations)]
4 use std::cell::RefCell;
5 #[cfg(span_locations)]
6 use std::cmp;
7 use std::fmt::{self, Debug, Display};
8 use std::iter::FromIterator;
9 use std::mem;
10 use std::ops::RangeBounds;
11 #[cfg(procmacro2_semver_exempt)]
12 use std::path::Path;
13 use std::path::PathBuf;
14 use std::str::FromStr;
15 use std::vec;
16 use unicode_xid::UnicodeXID;
17
18 /// Force use of proc-macro2's fallback implementation of the API for now, even
19 /// if the compiler's implementation is available.
20 pub fn force() {
21 #[cfg(wrap_proc_macro)]
22 crate::detection::force_fallback();
23 }
24
25 /// Resume using the compiler's implementation of the proc macro API if it is
26 /// available.
27 pub fn unforce() {
28 #[cfg(wrap_proc_macro)]
29 crate::detection::unforce_fallback();
30 }
31
32 #[derive(Clone)]
33 pub(crate) struct TokenStream {
34 pub(crate) inner: Vec<TokenTree>,
35 }
36
37 #[derive(Debug)]
38 pub(crate) struct LexError;
39
40 impl TokenStream {
41 pub fn new() -> TokenStream {
42 TokenStream { inner: Vec::new() }
43 }
44
45 pub fn is_empty(&self) -> bool {
46 self.inner.len() == 0
47 }
48
49 fn take_inner(&mut self) -> Vec<TokenTree> {
50 mem::replace(&mut self.inner, Vec::new())
51 }
52
53 fn push_token(&mut self, token: TokenTree) {
54 // https://github.com/alexcrichton/proc-macro2/issues/235
55 match token {
56 #[cfg(not(no_bind_by_move_pattern_guard))]
57 TokenTree::Literal(crate::Literal {
58 #[cfg(wrap_proc_macro)]
59 inner: crate::imp::Literal::Fallback(literal),
60 #[cfg(not(wrap_proc_macro))]
61 inner: literal,
62 ..
63 }) if literal.text.starts_with('-') => {
64 push_negative_literal(self, literal);
65 }
66 #[cfg(no_bind_by_move_pattern_guard)]
67 TokenTree::Literal(crate::Literal {
68 #[cfg(wrap_proc_macro)]
69 inner: crate::imp::Literal::Fallback(literal),
70 #[cfg(not(wrap_proc_macro))]
71 inner: literal,
72 ..
73 }) => {
74 if literal.text.starts_with('-') {
75 push_negative_literal(self, literal);
76 } else {
77 self.inner
78 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
79 }
80 }
81 _ => self.inner.push(token),
82 }
83
84 #[cold]
85 fn push_negative_literal(stream: &mut TokenStream, mut literal: Literal) {
86 literal.text.remove(0);
87 let mut punct = crate::Punct::new('-', Spacing::Alone);
88 punct.set_span(crate::Span::_new_stable(literal.span));
89 stream.inner.push(TokenTree::Punct(punct));
90 stream
91 .inner
92 .push(TokenTree::Literal(crate::Literal::_new_stable(literal)));
93 }
94 }
95 }
96
97 // Nonrecursive to prevent stack overflow.
98 impl Drop for TokenStream {
99 fn drop(&mut self) {
100 while let Some(token) = self.inner.pop() {
101 let group = match token {
102 TokenTree::Group(group) => group.inner,
103 _ => continue,
104 };
105 #[cfg(wrap_proc_macro)]
106 let group = match group {
107 crate::imp::Group::Fallback(group) => group,
108 _ => continue,
109 };
110 let mut group = group;
111 self.inner.extend(group.stream.take_inner());
112 }
113 }
114 }
115
116 #[cfg(span_locations)]
117 fn get_cursor(src: &str) -> Cursor {
118 // Create a dummy file & add it to the source map
119 SOURCE_MAP.with(|cm| {
120 let mut cm = cm.borrow_mut();
121 let name = format!("<parsed string {}>", cm.files.len());
122 let span = cm.add_file(&name, src);
123 Cursor {
124 rest: src,
125 off: span.lo,
126 }
127 })
128 }
129
130 #[cfg(not(span_locations))]
131 fn get_cursor(src: &str) -> Cursor {
132 Cursor { rest: src }
133 }
134
135 impl FromStr for TokenStream {
136 type Err = LexError;
137
138 fn from_str(src: &str) -> Result<TokenStream, LexError> {
139 // Create a dummy file & add it to the source map
140 let cursor = get_cursor(src);
141
142 let (rest, tokens) = token_stream(cursor)?;
143 if rest.is_empty() {
144 Ok(tokens)
145 } else {
146 Err(LexError)
147 }
148 }
149 }
150
151 impl Display for TokenStream {
152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 let mut joint = false;
154 for (i, tt) in self.inner.iter().enumerate() {
155 if i != 0 && !joint {
156 write!(f, " ")?;
157 }
158 joint = false;
159 match tt {
160 TokenTree::Group(tt) => Display::fmt(tt, f),
161 TokenTree::Ident(tt) => Display::fmt(tt, f),
162 TokenTree::Punct(tt) => {
163 joint = tt.spacing() == Spacing::Joint;
164 Display::fmt(tt, f)
165 }
166 TokenTree::Literal(tt) => Display::fmt(tt, f),
167 }?
168 }
169
170 Ok(())
171 }
172 }
173
174 impl Debug for TokenStream {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 f.write_str("TokenStream ")?;
177 f.debug_list().entries(self.clone()).finish()
178 }
179 }
180
181 #[cfg(use_proc_macro)]
182 impl From<proc_macro::TokenStream> for TokenStream {
183 fn from(inner: proc_macro::TokenStream) -> TokenStream {
184 inner
185 .to_string()
186 .parse()
187 .expect("compiler token stream parse failed")
188 }
189 }
190
191 #[cfg(use_proc_macro)]
192 impl From<TokenStream> for proc_macro::TokenStream {
193 fn from(inner: TokenStream) -> proc_macro::TokenStream {
194 inner
195 .to_string()
196 .parse()
197 .expect("failed to parse to compiler tokens")
198 }
199 }
200
201 impl From<TokenTree> for TokenStream {
202 fn from(tree: TokenTree) -> TokenStream {
203 let mut stream = TokenStream::new();
204 stream.push_token(tree);
205 stream
206 }
207 }
208
209 impl FromIterator<TokenTree> for TokenStream {
210 fn from_iter<I: IntoIterator<Item = TokenTree>>(tokens: I) -> Self {
211 let mut stream = TokenStream::new();
212 stream.extend(tokens);
213 stream
214 }
215 }
216
217 impl FromIterator<TokenStream> for TokenStream {
218 fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
219 let mut v = Vec::new();
220
221 for mut stream in streams {
222 v.extend(stream.take_inner());
223 }
224
225 TokenStream { inner: v }
226 }
227 }
228
229 impl Extend<TokenTree> for TokenStream {
230 fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, tokens: I) {
231 tokens.into_iter().for_each(|token| self.push_token(token));
232 }
233 }
234
235 impl Extend<TokenStream> for TokenStream {
236 fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
237 self.inner.extend(streams.into_iter().flatten());
238 }
239 }
240
241 pub(crate) type TokenTreeIter = vec::IntoIter<TokenTree>;
242
243 impl IntoIterator for TokenStream {
244 type Item = TokenTree;
245 type IntoIter = TokenTreeIter;
246
247 fn into_iter(mut self) -> TokenTreeIter {
248 self.take_inner().into_iter()
249 }
250 }
251
252 #[derive(Clone, PartialEq, Eq)]
253 pub(crate) struct SourceFile {
254 path: PathBuf,
255 }
256
257 impl SourceFile {
258 /// Get the path to this source file as a string.
259 pub fn path(&self) -> PathBuf {
260 self.path.clone()
261 }
262
263 pub fn is_real(&self) -> bool {
264 // XXX(nika): Support real files in the future?
265 false
266 }
267 }
268
269 impl Debug for SourceFile {
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 f.debug_struct("SourceFile")
272 .field("path", &self.path())
273 .field("is_real", &self.is_real())
274 .finish()
275 }
276 }
277
278 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
279 pub(crate) struct LineColumn {
280 pub line: usize,
281 pub column: usize,
282 }
283
284 #[cfg(span_locations)]
285 thread_local! {
286 static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {
287 // NOTE: We start with a single dummy file which all call_site() and
288 // def_site() spans reference.
289 files: vec![FileInfo {
290 #[cfg(procmacro2_semver_exempt)]
291 name: "<unspecified>".to_owned(),
292 span: Span { lo: 0, hi: 0 },
293 lines: vec![0],
294 }],
295 });
296 }
297
298 #[cfg(span_locations)]
299 struct FileInfo {
300 #[cfg(procmacro2_semver_exempt)]
301 name: String,
302 span: Span,
303 lines: Vec<usize>,
304 }
305
306 #[cfg(span_locations)]
307 impl FileInfo {
308 fn offset_line_column(&self, offset: usize) -> LineColumn {
309 assert!(self.span_within(Span {
310 lo: offset as u32,
311 hi: offset as u32
312 }));
313 let offset = offset - self.span.lo as usize;
314 match self.lines.binary_search(&offset) {
315 Ok(found) => LineColumn {
316 line: found + 1,
317 column: 0,
318 },
319 Err(idx) => LineColumn {
320 line: idx,
321 column: offset - self.lines[idx - 1],
322 },
323 }
324 }
325
326 fn span_within(&self, span: Span) -> bool {
327 span.lo >= self.span.lo && span.hi <= self.span.hi
328 }
329 }
330
331 /// Computes the offsets of each line in the given source string
332 /// and the total number of characters
333 #[cfg(span_locations)]
334 fn lines_offsets(s: &str) -> (usize, Vec<usize>) {
335 let mut lines = vec![0];
336 let mut total = 0;
337
338 for ch in s.chars() {
339 total += 1;
340 if ch == '\n' {
341 lines.push(total);
342 }
343 }
344
345 (total, lines)
346 }
347
348 #[cfg(span_locations)]
349 struct SourceMap {
350 files: Vec<FileInfo>,
351 }
352
353 #[cfg(span_locations)]
354 impl SourceMap {
355 fn next_start_pos(&self) -> u32 {
356 // Add 1 so there's always space between files.
357 //
358 // We'll always have at least 1 file, as we initialize our files list
359 // with a dummy file.
360 self.files.last().unwrap().span.hi + 1
361 }
362
363 fn add_file(&mut self, name: &str, src: &str) -> Span {
364 let (len, lines) = lines_offsets(src);
365 let lo = self.next_start_pos();
366 // XXX(nika): Shouild we bother doing a checked cast or checked add here?
367 let span = Span {
368 lo,
369 hi: lo + (len as u32),
370 };
371
372 self.files.push(FileInfo {
373 #[cfg(procmacro2_semver_exempt)]
374 name: name.to_owned(),
375 span,
376 lines,
377 });
378
379 #[cfg(not(procmacro2_semver_exempt))]
380 let _ = name;
381
382 span
383 }
384
385 fn fileinfo(&self, span: Span) -> &FileInfo {
386 for file in &self.files {
387 if file.span_within(span) {
388 return file;
389 }
390 }
391 panic!("Invalid span with no related FileInfo!");
392 }
393 }
394
395 #[derive(Clone, Copy, PartialEq, Eq)]
396 pub(crate) struct Span {
397 #[cfg(span_locations)]
398 pub(crate) lo: u32,
399 #[cfg(span_locations)]
400 pub(crate) hi: u32,
401 }
402
403 impl Span {
404 #[cfg(not(span_locations))]
405 pub fn call_site() -> Span {
406 Span {}
407 }
408
409 #[cfg(span_locations)]
410 pub fn call_site() -> Span {
411 Span { lo: 0, hi: 0 }
412 }
413
414 #[cfg(hygiene)]
415 pub fn mixed_site() -> Span {
416 Span::call_site()
417 }
418
419 #[cfg(procmacro2_semver_exempt)]
420 pub fn def_site() -> Span {
421 Span::call_site()
422 }
423
424 pub fn resolved_at(&self, _other: Span) -> Span {
425 // Stable spans consist only of line/column information, so
426 // `resolved_at` and `located_at` only select which span the
427 // caller wants line/column information from.
428 *self
429 }
430
431 pub fn located_at(&self, other: Span) -> Span {
432 other
433 }
434
435 #[cfg(procmacro2_semver_exempt)]
436 pub fn source_file(&self) -> SourceFile {
437 SOURCE_MAP.with(|cm| {
438 let cm = cm.borrow();
439 let fi = cm.fileinfo(*self);
440 SourceFile {
441 path: Path::new(&fi.name).to_owned(),
442 }
443 })
444 }
445
446 #[cfg(span_locations)]
447 pub fn start(&self) -> LineColumn {
448 SOURCE_MAP.with(|cm| {
449 let cm = cm.borrow();
450 let fi = cm.fileinfo(*self);
451 fi.offset_line_column(self.lo as usize)
452 })
453 }
454
455 #[cfg(span_locations)]
456 pub fn end(&self) -> LineColumn {
457 SOURCE_MAP.with(|cm| {
458 let cm = cm.borrow();
459 let fi = cm.fileinfo(*self);
460 fi.offset_line_column(self.hi as usize)
461 })
462 }
463
464 #[cfg(not(span_locations))]
465 pub fn join(&self, _other: Span) -> Option<Span> {
466 Some(Span {})
467 }
468
469 #[cfg(span_locations)]
470 pub fn join(&self, other: Span) -> Option<Span> {
471 SOURCE_MAP.with(|cm| {
472 let cm = cm.borrow();
473 // If `other` is not within the same FileInfo as us, return None.
474 if !cm.fileinfo(*self).span_within(other) {
475 return None;
476 }
477 Some(Span {
478 lo: cmp::min(self.lo, other.lo),
479 hi: cmp::max(self.hi, other.hi),
480 })
481 })
482 }
483
484 #[cfg(not(span_locations))]
485 fn first_byte(self) -> Self {
486 self
487 }
488
489 #[cfg(span_locations)]
490 fn first_byte(self) -> Self {
491 Span {
492 lo: self.lo,
493 hi: cmp::min(self.lo.saturating_add(1), self.hi),
494 }
495 }
496
497 #[cfg(not(span_locations))]
498 fn last_byte(self) -> Self {
499 self
500 }
501
502 #[cfg(span_locations)]
503 fn last_byte(self) -> Self {
504 Span {
505 lo: cmp::max(self.hi.saturating_sub(1), self.lo),
506 hi: self.hi,
507 }
508 }
509 }
510
511 impl Debug for Span {
512 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513 #[cfg(span_locations)]
514 return write!(f, "bytes({}..{})", self.lo, self.hi);
515
516 #[cfg(not(span_locations))]
517 write!(f, "Span")
518 }
519 }
520
521 pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
522 #[cfg(span_locations)]
523 {
524 if span.lo == 0 && span.hi == 0 {
525 return;
526 }
527 }
528
529 if cfg!(span_locations) {
530 debug.field("span", &span);
531 }
532 }
533
534 #[derive(Clone)]
535 pub(crate) struct Group {
536 delimiter: Delimiter,
537 stream: TokenStream,
538 span: Span,
539 }
540
541 impl Group {
542 pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
543 Group {
544 delimiter,
545 stream,
546 span: Span::call_site(),
547 }
548 }
549
550 pub fn delimiter(&self) -> Delimiter {
551 self.delimiter
552 }
553
554 pub fn stream(&self) -> TokenStream {
555 self.stream.clone()
556 }
557
558 pub fn span(&self) -> Span {
559 self.span
560 }
561
562 pub fn span_open(&self) -> Span {
563 self.span.first_byte()
564 }
565
566 pub fn span_close(&self) -> Span {
567 self.span.last_byte()
568 }
569
570 pub fn set_span(&mut self, span: Span) {
571 self.span = span;
572 }
573 }
574
575 impl Display for Group {
576 // We attempt to match libproc_macro's formatting.
577 // Empty parens: ()
578 // Nonempty parens: (...)
579 // Empty brackets: []
580 // Nonempty brackets: [...]
581 // Empty braces: { }
582 // Nonempty braces: { ... }
583 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584 let (open, close) = match self.delimiter {
585 Delimiter::Parenthesis => ("(", ")"),
586 Delimiter::Brace => ("{ ", "}"),
587 Delimiter::Bracket => ("[", "]"),
588 Delimiter::None => ("", ""),
589 };
590
591 f.write_str(open)?;
592 Display::fmt(&self.stream, f)?;
593 if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() {
594 f.write_str(" ")?;
595 }
596 f.write_str(close)?;
597
598 Ok(())
599 }
600 }
601
602 impl Debug for Group {
603 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
604 let mut debug = fmt.debug_struct("Group");
605 debug.field("delimiter", &self.delimiter);
606 debug.field("stream", &self.stream);
607 debug_span_field_if_nontrivial(&mut debug, self.span);
608 debug.finish()
609 }
610 }
611
612 #[derive(Clone)]
613 pub(crate) struct Ident {
614 sym: String,
615 span: Span,
616 raw: bool,
617 }
618
619 impl Ident {
620 fn _new(string: &str, raw: bool, span: Span) -> Ident {
621 validate_ident(string);
622
623 Ident {
624 sym: string.to_owned(),
625 span,
626 raw,
627 }
628 }
629
630 pub fn new(string: &str, span: Span) -> Ident {
631 Ident::_new(string, false, span)
632 }
633
634 pub fn new_raw(string: &str, span: Span) -> Ident {
635 Ident::_new(string, true, span)
636 }
637
638 pub fn span(&self) -> Span {
639 self.span
640 }
641
642 pub fn set_span(&mut self, span: Span) {
643 self.span = span;
644 }
645 }
646
647 pub(crate) fn is_ident_start(c: char) -> bool {
648 ('a' <= c && c <= 'z')
649 || ('A' <= c && c <= 'Z')
650 || c == '_'
651 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
652 }
653
654 pub(crate) fn is_ident_continue(c: char) -> bool {
655 ('a' <= c && c <= 'z')
656 || ('A' <= c && c <= 'Z')
657 || c == '_'
658 || ('0' <= c && c <= '9')
659 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
660 }
661
662 fn validate_ident(string: &str) {
663 let validate = string;
664 if validate.is_empty() {
665 panic!("Ident is not allowed to be empty; use Option<Ident>");
666 }
667
668 if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
669 panic!("Ident cannot be a number; use Literal instead");
670 }
671
672 fn ident_ok(string: &str) -> bool {
673 let mut chars = string.chars();
674 let first = chars.next().unwrap();
675 if !is_ident_start(first) {
676 return false;
677 }
678 for ch in chars {
679 if !is_ident_continue(ch) {
680 return false;
681 }
682 }
683 true
684 }
685
686 if !ident_ok(validate) {
687 panic!("{:?} is not a valid Ident", string);
688 }
689 }
690
691 impl PartialEq for Ident {
692 fn eq(&self, other: &Ident) -> bool {
693 self.sym == other.sym && self.raw == other.raw
694 }
695 }
696
697 impl<T> PartialEq<T> for Ident
698 where
699 T: ?Sized + AsRef<str>,
700 {
701 fn eq(&self, other: &T) -> bool {
702 let other = other.as_ref();
703 if self.raw {
704 other.starts_with("r#") && self.sym == other[2..]
705 } else {
706 self.sym == other
707 }
708 }
709 }
710
711 impl Display for Ident {
712 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
713 if self.raw {
714 f.write_str("r#")?;
715 }
716 Display::fmt(&self.sym, f)
717 }
718 }
719
720 impl Debug for Ident {
721 // Ident(proc_macro), Ident(r#union)
722 #[cfg(not(span_locations))]
723 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
724 let mut debug = f.debug_tuple("Ident");
725 debug.field(&format_args!("{}", self));
726 debug.finish()
727 }
728
729 // Ident {
730 // sym: proc_macro,
731 // span: bytes(128..138)
732 // }
733 #[cfg(span_locations)]
734 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
735 let mut debug = f.debug_struct("Ident");
736 debug.field("sym", &format_args!("{}", self));
737 debug_span_field_if_nontrivial(&mut debug, self.span);
738 debug.finish()
739 }
740 }
741
742 #[derive(Clone)]
743 pub(crate) struct Literal {
744 text: String,
745 span: Span,
746 }
747
748 macro_rules! suffixed_numbers {
749 ($($name:ident => $kind:ident,)*) => ($(
750 pub fn $name(n: $kind) -> Literal {
751 Literal::_new(format!(concat!("{}", stringify!($kind)), n))
752 }
753 )*)
754 }
755
756 macro_rules! unsuffixed_numbers {
757 ($($name:ident => $kind:ident,)*) => ($(
758 pub fn $name(n: $kind) -> Literal {
759 Literal::_new(n.to_string())
760 }
761 )*)
762 }
763
764 impl Literal {
765 pub(crate) fn _new(text: String) -> Literal {
766 Literal {
767 text,
768 span: Span::call_site(),
769 }
770 }
771
772 suffixed_numbers! {
773 u8_suffixed => u8,
774 u16_suffixed => u16,
775 u32_suffixed => u32,
776 u64_suffixed => u64,
777 u128_suffixed => u128,
778 usize_suffixed => usize,
779 i8_suffixed => i8,
780 i16_suffixed => i16,
781 i32_suffixed => i32,
782 i64_suffixed => i64,
783 i128_suffixed => i128,
784 isize_suffixed => isize,
785
786 f32_suffixed => f32,
787 f64_suffixed => f64,
788 }
789
790 unsuffixed_numbers! {
791 u8_unsuffixed => u8,
792 u16_unsuffixed => u16,
793 u32_unsuffixed => u32,
794 u64_unsuffixed => u64,
795 u128_unsuffixed => u128,
796 usize_unsuffixed => usize,
797 i8_unsuffixed => i8,
798 i16_unsuffixed => i16,
799 i32_unsuffixed => i32,
800 i64_unsuffixed => i64,
801 i128_unsuffixed => i128,
802 isize_unsuffixed => isize,
803 }
804
805 pub fn f32_unsuffixed(f: f32) -> Literal {
806 let mut s = f.to_string();
807 if !s.contains('.') {
808 s.push_str(".0");
809 }
810 Literal::_new(s)
811 }
812
813 pub fn f64_unsuffixed(f: f64) -> Literal {
814 let mut s = f.to_string();
815 if !s.contains('.') {
816 s.push_str(".0");
817 }
818 Literal::_new(s)
819 }
820
821 pub fn string(t: &str) -> Literal {
822 let mut text = String::with_capacity(t.len() + 2);
823 text.push('"');
824 for c in t.chars() {
825 if c == '\'' {
826 // escape_debug turns this into "\'" which is unnecessary.
827 text.push(c);
828 } else {
829 text.extend(c.escape_debug());
830 }
831 }
832 text.push('"');
833 Literal::_new(text)
834 }
835
836 pub fn character(t: char) -> Literal {
837 let mut text = String::new();
838 text.push('\'');
839 if t == '"' {
840 // escape_debug turns this into '\"' which is unnecessary.
841 text.push(t);
842 } else {
843 text.extend(t.escape_debug());
844 }
845 text.push('\'');
846 Literal::_new(text)
847 }
848
849 pub fn byte_string(bytes: &[u8]) -> Literal {
850 let mut escaped = "b\"".to_string();
851 for b in bytes {
852 #[allow(clippy::match_overlapping_arm)]
853 match *b {
854 b'\0' => escaped.push_str(r"\0"),
855 b'\t' => escaped.push_str(r"\t"),
856 b'\n' => escaped.push_str(r"\n"),
857 b'\r' => escaped.push_str(r"\r"),
858 b'"' => escaped.push_str("\\\""),
859 b'\\' => escaped.push_str("\\\\"),
860 b'\x20'..=b'\x7E' => escaped.push(*b as char),
861 _ => escaped.push_str(&format!("\\x{:02X}", b)),
862 }
863 }
864 escaped.push('"');
865 Literal::_new(escaped)
866 }
867
868 pub fn span(&self) -> Span {
869 self.span
870 }
871
872 pub fn set_span(&mut self, span: Span) {
873 self.span = span;
874 }
875
876 pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
877 None
878 }
879 }
880
881 impl Display for Literal {
882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883 Display::fmt(&self.text, f)
884 }
885 }
886
887 impl Debug for Literal {
888 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
889 let mut debug = fmt.debug_struct("Literal");
890 debug.field("lit", &format_args!("{}", self.text));
891 debug_span_field_if_nontrivial(&mut debug, self.span);
892 debug.finish()
893 }
894 }