22/// supported platforms. 
33
44use  crate :: env; 
5+ use  crate :: fmt; 
56use  crate :: io; 
67use  crate :: io:: prelude:: * ; 
7- use  crate :: mem; 
88use  crate :: path:: { self ,  Path } ; 
9- use  crate :: ptr; 
109use  crate :: sync:: atomic:: { self ,  Ordering } ; 
1110use  crate :: sys:: mutex:: Mutex ; 
1211
13- use  backtrace:: { BytesOrWideString ,  Frame ,  Symbol } ; 
14- 
15- pub  const  HEX_WIDTH :  usize  = 2  + 2  *  mem:: size_of :: < usize > ( ) ; 
12+ use  backtrace:: { BacktraceFmt ,  BytesOrWideString ,  PrintFmt } ; 
1613
1714/// Max number of frames to print. 
1815const  MAX_NB_FRAMES :  usize  = 100 ; 
1916
2017/// Prints the current backtrace. 
21- pub  fn  print ( w :  & mut  dyn  Write ,  format :  PrintFormat )  -> io:: Result < ( ) >  { 
18+ pub  fn  print ( w :  & mut  dyn  Write ,  format :  PrintFmt )  -> io:: Result < ( ) >  { 
2219    static  LOCK :  Mutex  = Mutex :: new ( ) ; 
2320
2421    // There are issues currently linking libbacktrace into tests, and in 
@@ -39,26 +36,66 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
3936    } 
4037} 
4138
42- fn  _print ( w :  & mut  dyn  Write ,  format :  PrintFormat )  -> io:: Result < ( ) >  { 
43-     writeln ! ( w,  "stack backtrace:" ) ?; 
39+ fn  _print ( w :  & mut  dyn  Write ,  format :  PrintFmt )  -> io:: Result < ( ) >  { 
40+     struct  DisplayBacktrace  { 
41+         format :  PrintFmt , 
42+     } 
43+     impl  fmt:: Display  for  DisplayBacktrace  { 
44+         fn  fmt ( & self ,  fmt :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
45+             _print_fmt ( fmt,  self . format ) 
46+         } 
47+     } 
48+     write ! ( w,  "{}" ,  DisplayBacktrace  {  format } ) 
49+ } 
4450
45-     let  mut  printer = Printer :: new ( format,  w) ; 
51+ fn  _print_fmt ( fmt :  & mut  fmt:: Formatter < ' _ > ,  print_fmt :  PrintFmt )  -> fmt:: Result  { 
52+     let  mut  print_path = move  |fmt :  & mut  fmt:: Formatter < ' _ > ,  bows :  BytesOrWideString < ' _ > | { 
53+         output_filename ( fmt,  bows,  print_fmt) 
54+     } ; 
55+     let  mut  bt_fmt = BacktraceFmt :: new ( fmt,  print_fmt,  & mut  print_path) ; 
56+     bt_fmt. add_context ( ) ?; 
57+     let  mut  skipped = false ; 
4658    unsafe  { 
59+         let  mut  idx = 0 ; 
60+         let  mut  res = Ok ( ( ) ) ; 
4761        backtrace:: trace_unsynchronized ( |frame| { 
62+             if  print_fmt == PrintFmt :: Short  && idx > MAX_NB_FRAMES  { 
63+                 skipped = true ; 
64+                 return  false ; 
65+             } 
66+ 
4867            let  mut  hit = false ; 
68+             let  mut  stop = false ; 
4969            backtrace:: resolve_frame_unsynchronized ( frame,  |symbol| { 
5070                hit = true ; 
51-                 printer. output ( frame,  Some ( symbol) ) ; 
71+                 if  print_fmt == PrintFmt :: Short  { 
72+                     if  let  Some ( sym)  = symbol. name ( ) . and_then ( |s| s. as_str ( ) )  { 
73+                         if  sym. contains ( "__rust_begin_short_backtrace" )  { 
74+                             skipped = true ; 
75+                             stop = true ; 
76+                             return ; 
77+                         } 
78+                     } 
79+                 } 
80+ 
81+                 res = bt_fmt. frame ( ) . symbol ( frame,  symbol) ; 
5282            } ) ; 
83+             if  stop { 
84+                 return  false ; 
85+             } 
5386            if  !hit { 
54-                 printer . output ( frame,  None ) ; 
87+                 res = bt_fmt . frame ( ) . print_raw ( frame. ip ( ) ,   None ,   None ,  None ) ; 
5588            } 
56-             !printer. done 
89+ 
90+             idx += 1 ; 
91+             res. is_ok ( ) 
5792        } ) ; 
93+         res?; 
5894    } 
59-     if  printer. skipped  { 
95+     bt_fmt. finish ( ) ?; 
96+     if  skipped { 
6097        writeln ! ( 
61-             w , 
98+             fmt , 
6299            "note: Some details are omitted, \  
63100
64101        ) ?; 
@@ -77,33 +114,24 @@ where
77114    f ( ) 
78115} 
79116
80- /// Controls how the backtrace should be formatted. 
81- #[ derive( Debug ,  Copy ,  Clone ,  Eq ,  PartialEq ) ]  
82- pub  enum  PrintFormat  { 
83-     /// Show only relevant data from the backtrace. 
84- Short  = 2 , 
85-     /// Show all the frames with absolute path for files. 
86- Full  = 3 , 
87- } 
88- 
89117// For now logging is turned off by default, and this function checks to see 
90118// whether the magical environment variable is present to see if it's turned on. 
91- pub  fn  log_enabled ( )  -> Option < PrintFormat >  { 
119+ pub  fn  log_enabled ( )  -> Option < PrintFmt >  { 
92120    static  ENABLED :  atomic:: AtomicIsize  = atomic:: AtomicIsize :: new ( 0 ) ; 
93121    match  ENABLED . load ( Ordering :: SeqCst )  { 
94122        0  => { } 
95123        1  => return  None , 
96-         2  => return  Some ( PrintFormat :: Short ) , 
97-         _ => return  Some ( PrintFormat :: Full ) , 
124+         2  => return  Some ( PrintFmt :: Short ) , 
125+         _ => return  Some ( PrintFmt :: Full ) , 
98126    } 
99127
100128    let  val = env:: var_os ( "RUST_BACKTRACE" ) . and_then ( |x| { 
101129        if  & x == "0"  { 
102130            None 
103131        }  else  if  & x == "full"  { 
104-             Some ( PrintFormat :: Full ) 
132+             Some ( PrintFmt :: Full ) 
105133        }  else  { 
106-             Some ( PrintFormat :: Short ) 
134+             Some ( PrintFmt :: Short ) 
107135        } 
108136    } ) ; 
109137    ENABLED . store ( 
@@ -116,130 +144,45 @@ pub fn log_enabled() -> Option<PrintFormat> {
116144    val
117145} 
118146
119- struct  Printer < ' a ,  ' b >  { 
120-     format :  PrintFormat , 
121-     done :  bool , 
122-     skipped :  bool , 
123-     idx :  usize , 
124-     out :  & ' a  mut  ( dyn  Write  + ' b ) , 
125- } 
126- 
127- impl < ' a ,  ' b >  Printer < ' a ,  ' b >  { 
128-     fn  new ( format :  PrintFormat ,  out :  & ' a  mut  ( dyn  Write  + ' b ) )  -> Printer < ' a ,  ' b >  { 
129-         Printer  {  format,  done :  false ,  skipped :  false ,  idx :  0 ,  out } 
130-     } 
131- 
132-     /// Prints the symbol of the backtrace frame. 
133- /// 
134- /// These output functions should now be used everywhere to ensure consistency. 
135- /// You may want to also use `output_fileline`. 
136- fn  output ( & mut  self ,  frame :  & Frame ,  symbol :  Option < & Symbol > )  { 
137-         if  self . idx  > MAX_NB_FRAMES  { 
138-             self . done  = true ; 
139-             self . skipped  = true ; 
140-             return ; 
141-         } 
142-         if  self . _output ( frame,  symbol) . is_err ( )  { 
143-             self . done  = true ; 
144-         } 
145-         self . idx  += 1 ; 
146-     } 
147- 
148-     fn  _output ( & mut  self ,  frame :  & Frame ,  symbol :  Option < & Symbol > )  -> io:: Result < ( ) >  { 
149-         if  self . format  == PrintFormat :: Short  { 
150-             if  let  Some ( sym)  = symbol. and_then ( |s| s. name ( ) ) . and_then ( |s| s. as_str ( ) )  { 
151-                 if  sym. contains ( "__rust_begin_short_backtrace" )  { 
152-                     self . skipped  = true ; 
153-                     self . done  = true ; 
154-                     return  Ok ( ( ) ) ; 
155-                 } 
156-             } 
157- 
158-             // Remove the `17: 0x0 - <unknown>` line. 
159-             if  self . format  == PrintFormat :: Short  && frame. ip ( )  == ptr:: null_mut ( )  { 
160-                 self . skipped  = true ; 
161-                 return  Ok ( ( ) ) ; 
162-             } 
163-         } 
164- 
165-         match  self . format  { 
166-             PrintFormat :: Full  => { 
167-                 write ! ( self . out,  "  {:2}: {:2$?} - " ,  self . idx,  frame. ip( ) ,  HEX_WIDTH ) ?
168-             } 
169-             PrintFormat :: Short  => write ! ( self . out,  "  {:2}: " ,  self . idx) ?, 
170-         } 
171- 
172-         match  symbol. and_then ( |s| s. name ( ) )  { 
173-             Some ( symbol)  => { 
174-                 match  self . format  { 
175-                     PrintFormat :: Full  => write ! ( self . out,  "{}" ,  symbol) ?, 
176-                     // Strip the trailing hash if short mode. 
177-                     PrintFormat :: Short  => write ! ( self . out,  "{:#}" ,  symbol) ?, 
178-                 } 
179-             } 
180-             None  => self . out . write_all ( b"<unknown>" ) ?, 
147+ /// Prints the filename of the backtrace frame. 
148+ /// 
149+ /// See also `output`. 
150+ fn  output_filename ( 
151+     fmt :  & mut  fmt:: Formatter < ' _ > , 
152+     bows :  BytesOrWideString < ' _ > , 
153+     print_fmt :  PrintFmt , 
154+ )  -> fmt:: Result  { 
155+     #[ cfg( windows) ]  
156+     let  path_buf; 
157+     let  file = match  bows { 
158+         #[ cfg( unix) ]  
159+         BytesOrWideString :: Bytes ( bytes)  => { 
160+             use  crate :: os:: unix:: prelude:: * ; 
161+             Path :: new ( crate :: ffi:: OsStr :: from_bytes ( bytes) ) 
181162        } 
182-         self . out . write_all ( b" \n " ) ? ; 
183-         if   let   Some ( sym )  = symbol  { 
184-             self . output_fileline ( sym ) ? ; 
163+         # [ cfg ( not ( unix ) ) ] 
164+         BytesOrWideString :: Bytes ( bytes )  =>  { 
165+             Path :: new ( crate :: str :: from_utf8 ( bytes ) . unwrap_or ( "<unknown>" ) ) 
185166        } 
186-         Ok ( ( ) ) 
187-     } 
188- 
189-     /// Prints the filename and line number of the backtrace frame. 
190- /// 
191- /// See also `output`. 
192- fn  output_fileline ( & mut  self ,  symbol :  & Symbol )  -> io:: Result < ( ) >  { 
193167        #[ cfg( windows) ]  
194-         let  path_buf; 
195-         let  file = match  symbol. filename_raw ( )  { 
196-             #[ cfg( unix) ]  
197-             Some ( BytesOrWideString :: Bytes ( bytes) )  => { 
198-                 use  crate :: os:: unix:: prelude:: * ; 
199-                 Path :: new ( crate :: ffi:: OsStr :: from_bytes ( bytes) ) 
200-             } 
201-             #[ cfg( not( unix) ) ]  
202-             Some ( BytesOrWideString :: Bytes ( bytes) )  => { 
203-                 Path :: new ( crate :: str:: from_utf8 ( bytes) . unwrap_or ( "<unknown>" ) ) 
204-             } 
205-             #[ cfg( windows) ]  
206-             Some ( BytesOrWideString :: Wide ( wide) )  => { 
207-                 use  crate :: os:: windows:: prelude:: * ; 
208-                 path_buf = crate :: ffi:: OsString :: from_wide ( wide) ; 
209-                 Path :: new ( & path_buf) 
210-             } 
211-             #[ cfg( not( windows) ) ]  
212-             Some ( BytesOrWideString :: Wide ( _wide) )  => { 
213-                 Path :: new ( "<unknown>" ) 
214-             } 
215-             None  => return  Ok ( ( ) ) , 
216-         } ; 
217-         let  line = match  symbol. lineno ( )  { 
218-             Some ( line)  => line, 
219-             None  => return  Ok ( ( ) ) , 
220-         } ; 
221-         // prior line: "  ##: {:2$} - func" 
222-         self . out . write_all ( b"" ) ?; 
223-         match  self . format  { 
224-             PrintFormat :: Full  => write ! ( self . out,  "           {:1$}" ,  "" ,  HEX_WIDTH ) ?, 
225-             PrintFormat :: Short  => write ! ( self . out,  "           " ) ?, 
168+         BytesOrWideString :: Wide ( wide)  => { 
169+             use  crate :: os:: windows:: prelude:: * ; 
170+             path_buf = crate :: ffi:: OsString :: from_wide ( wide) ; 
171+             Path :: new ( & path_buf) 
226172        } 
227- 
228-         let  mut  already_printed = false ; 
229-         if  self . format  == PrintFormat :: Short  && file. is_absolute ( )  { 
230-             if  let  Ok ( cwd)  = env:: current_dir ( )  { 
231-                 if  let  Ok ( stripped)  = file. strip_prefix ( & cwd)  { 
232-                     if  let  Some ( s)  = stripped. to_str ( )  { 
233-                         write ! ( self . out,  "  at .{}{}:{}" ,  path:: MAIN_SEPARATOR ,  s,  line) ?; 
234-                         already_printed = true ; 
235-                     } 
173+         #[ cfg( not( windows) ) ]  
174+         BytesOrWideString :: Wide ( _wide)  => { 
175+             Path :: new ( "<unknown>" ) 
176+         } 
177+     } ; 
178+     if  print_fmt == PrintFmt :: Short  && file. is_absolute ( )  { 
179+         if  let  Ok ( cwd)  = env:: current_dir ( )  { 
180+             if  let  Ok ( stripped)  = file. strip_prefix ( & cwd)  { 
181+                 if  let  Some ( s)  = stripped. to_str ( )  { 
182+                     return  write ! ( fmt,  ".{}{}" ,  path:: MAIN_SEPARATOR ,  s) ; 
236183                } 
237184            } 
238185        } 
239-         if  !already_printed { 
240-             write ! ( self . out,  "  at {}:{}" ,  file. display( ) ,  line) ?; 
241-         } 
242- 
243-         self . out . write_all ( b"\n " ) 
244186    } 
187+     fmt:: Display :: fmt ( & file. display ( ) ,  fmt) 
245188} 
0 commit comments