1 use core::fmt; 2 3 #[cfg(feature = "alloc")] 4 use alloc::vec::Vec; 5 6 /// Helper struct to send console output to GDB. 7 /// 8 /// The recommended way to interact with `ConsoleOutput` is through the provided 9 /// [`output!`](macro.output.html) / [`outputln!`](macro.outputln.html) macros. 10 /// 11 /// On resource constrained systems which might want to avoid using Rust's 12 /// [fairly "heavy" formatting machinery](https://jamesmunns.com/blog/fmt-unreasonably-expensive/), 13 /// the `write_raw()` method can be used to write raw data directly to the GDB 14 /// console. 15 /// 16 /// When the `alloc` feature is disabled, all output buffering is disabled, and 17 /// each call to `output!` will automatically flush data over the Connection. 18 // TODO: support user-provided output buffers for no-`alloc` environments. 19 pub struct ConsoleOutput<'a> { 20 #[cfg(feature = "alloc")] 21 buf: Vec<u8>, 22 callback: &'a mut dyn FnMut(&[u8]), 23 } 24 25 impl<'a> fmt::Write for ConsoleOutput<'a> { write_str(&mut self, s: &str) -> fmt::Result26 fn write_str(&mut self, s: &str) -> fmt::Result { 27 self.write_raw(s.as_bytes()); 28 Ok(()) 29 } 30 } 31 32 impl<'a> ConsoleOutput<'a> { new(callback: &'a mut dyn FnMut(&[u8])) -> ConsoleOutput<'a>33 pub(crate) fn new(callback: &'a mut dyn FnMut(&[u8])) -> ConsoleOutput<'a> { 34 ConsoleOutput { 35 #[cfg(feature = "alloc")] 36 buf: Vec::new(), 37 callback, 38 } 39 } 40 41 /// Write raw (non UTF-8) data to the GDB console. write_raw(&mut self, bytes: &[u8])42 pub fn write_raw(&mut self, bytes: &[u8]) { 43 cfg_if::cfg_if! { 44 if #[cfg(feature = "alloc")] { 45 self.buf.extend_from_slice(bytes); 46 } else { 47 (self.callback)(bytes); 48 } 49 } 50 } 51 52 /// Flush the internal output buffer. 53 /// 54 /// Only available when `alloc` is enabled. 55 #[cfg(feature = "alloc")] flush(&mut self)56 pub fn flush(&mut self) { 57 if !self.buf.is_empty() { 58 (self.callback)(&self.buf); 59 self.buf.clear() 60 } 61 } 62 } 63 64 impl Drop for ConsoleOutput<'_> { drop(&mut self)65 fn drop(&mut self) { 66 #[cfg(feature = "alloc")] 67 self.flush() 68 } 69 } 70 71 /// Send formatted data to the GDB client console. 72 /// 73 /// The first argument must be a [`ConsoleWriter`](struct.ConsoleWriter.html). 74 #[macro_export] 75 macro_rules! output { 76 ($console_output:expr, $($args:tt)*) => {{ 77 use std::fmt::Write; 78 let _ = write!($console_output, $($args)*); 79 }}; 80 } 81 82 /// Send formatted data to the GDB client console, with a newline appended. 83 /// 84 /// The first argument must be a [`ConsoleWriter`](struct.ConsoleWriter.html). 85 #[macro_export] 86 macro_rules! outputln { 87 ($console_output:expr) => {{ 88 use core::fmt::Write; 89 let _ = writeln!($console_output); 90 }}; 91 ($console_output:expr,) => { 92 outputln!($console_output) 93 }; 94 ($console_output:expr, $($args:tt)*) => {{ 95 use core::fmt::Write; 96 let _ = writeln!($console_output, $($args)*); 97 }}; 98 } 99