@@ -146,19 +146,24 @@ pub fn demangle(mut s: &str) -> Demangle {
146146}
147147
148148#[ cfg( feature = "std" ) ]
149- fn demangle_line ( line : & str , include_hash : bool ) -> std:: borrow:: Cow < str > {
150- let mut line = std:: borrow:: Cow :: Borrowed ( line) ;
149+ fn demangle_line (
150+ line : & str ,
151+ output : & mut impl std:: io:: Write ,
152+ include_hash : bool ,
153+ ) -> std:: io:: Result < ( ) > {
151154 let mut head = 0 ;
152- loop {
155+ while head < line . len ( ) {
153156 // Move to the next potential match
154- head = match ( line[ head..] . find ( "_ZN" ) , line[ head..] . find ( "_R" ) ) {
157+ let next_head = match ( line[ head..] . find ( "_ZN" ) , line[ head..] . find ( "_R" ) ) {
155158 ( Some ( idx) , None ) | ( None , Some ( idx) ) => head + idx,
156159 ( Some ( idx1) , Some ( idx2) ) => head + idx1. min ( idx2) ,
157160 ( None , None ) => {
158- // No more matches, we can return our line .
159- return line;
161+ // No more matches.. .
162+ line. len ( )
160163 }
161164 } ;
165+ output. write_all ( line[ head..next_head] . as_bytes ( ) ) ?;
166+ head = next_head;
162167 // Find the non-matching character.
163168 //
164169 // If we do not find a character, then until the end of the line is the
@@ -169,29 +174,26 @@ fn demangle_line(line: &str, include_hash: bool) -> std::borrow::Cow<str> {
169174 . unwrap_or ( line. len ( ) ) ;
170175
171176 let mangled = & line[ head..match_end] ;
177+ head = head + mangled. len ( ) ;
172178 if let Ok ( demangled) = try_demangle ( mangled) {
173- let demangled = if include_hash {
174- format ! ( "{}" , demangled)
179+ if include_hash {
180+ write ! ( output , "{}" , demangled) ? ;
175181 } else {
176- format ! ( "{:#}" , demangled)
177- } ;
178- line. to_mut ( ) . replace_range ( head..match_end, & demangled) ;
179- // Start again after the replacement.
180- head = head + demangled. len ( ) ;
182+ write ! ( output, "{:#}" , demangled) ?;
183+ }
181184 } else {
182- // Skip over the full symbol. We don't try to find a partial Rust symbol in the wider
183- // matched text today.
184- head = head + mangled. len ( ) ;
185+ output. write_all ( mangled. as_bytes ( ) ) ?;
185186 }
186187 }
188+ Ok ( ( ) )
187189}
188190
189191/// Process a stream of data from `input` into the provided `output`, demangling any symbols found
190192/// within.
191193///
192- /// This currently is implemented by buffering each line of input in memory, but that may be
193- /// changed in the future. Symbols never cross line boundaries so this is just an implementation
194- /// detail .
194+ /// Note that the underlying implementation will perform many relatively small writes to the
195+ /// output. If the output is expensive to write to (e.g., requires syscalls), consider using
196+ /// `std::io::BufWriter` .
195197#[ cfg( feature = "std" ) ]
196198#[ cfg_attr( docsrs, doc( cfg( feature = "std" ) ) ) ]
197199pub fn demangle_stream < R : std:: io:: BufRead , W : std:: io:: Write > (
@@ -206,8 +208,7 @@ pub fn demangle_stream<R: std::io::BufRead, W: std::io::Write>(
206208 // trailing data during demangling. In the future we might directly stream to the output but at
207209 // least right now that seems to be less efficient.
208210 while input. read_line ( & mut buf) ? > 0 {
209- let demangled_line = demangle_line ( & buf, include_hash) ;
210- output. write_all ( demangled_line. as_bytes ( ) ) ?;
211+ demangle_line ( & buf, output, include_hash) ?;
211212 buf. clear ( ) ;
212213 }
213214 Ok ( ( ) )
@@ -560,11 +561,18 @@ mod tests {
560561 ) ;
561562 }
562563
564+ #[ cfg( feature = "std" ) ]
565+ fn demangle_str ( input : & str ) -> String {
566+ let mut output = Vec :: new ( ) ;
567+ super :: demangle_line ( input, & mut output, false ) ;
568+ String :: from_utf8 ( output) . unwrap ( )
569+ }
570+
563571 #[ test]
564572 #[ cfg( feature = "std" ) ]
565573 fn find_multiple ( ) {
566574 assert_eq ! (
567- super :: demangle_line ( "_ZN3fooE.llvm moocow _ZN3fooE.llvm" , false ) ,
575+ demangle_str ( "_ZN3fooE.llvm moocow _ZN3fooE.llvm" ) ,
568576 "foo.llvm moocow foo.llvm"
569577 ) ;
570578 }
@@ -573,7 +581,7 @@ mod tests {
573581 #[ cfg( feature = "std" ) ]
574582 fn interleaved_new_legacy ( ) {
575583 assert_eq ! (
576- super :: demangle_line ( "_ZN3fooE.llvm moocow _RNvMNtNtNtNtCs8a2262Dv4r_3mio3sys4unix8selector5epollNtB2_8Selector6select _ZN3fooE.llvm" , false ) ,
584+ demangle_str ( "_ZN3fooE.llvm moocow _RNvMNtNtNtNtCs8a2262Dv4r_3mio3sys4unix8selector5epollNtB2_8Selector6select _ZN3fooE.llvm" ) ,
577585 "foo.llvm moocow <mio::sys::unix::selector::epoll::Selector>::select foo.llvm"
578586 ) ;
579587 }
0 commit comments