1 //! Allocator logging. 2 //! 3 //! This allows for detailed logging for `ralloc`. 4 5 /// Log to the appropriate source. 6 /// 7 /// The first argument this takes is of the form `pool;cursor`, which is used to print the 8 /// block pools state. `cursor` is what the operation "revolves around" to give a sense of 9 /// position. 10 /// 11 /// If the `;cursor` part is left out, no cursor will be printed. 12 /// 13 /// The rest of the arguments are just normal formatters. 14 #[macro_export] 15 macro_rules! log { 16 ($pool:expr, $( $arg:expr ),*) => { 17 log!($pool;(), $( $arg ),*); 18 }; 19 ($bk:expr;$cur:expr, $( $arg:expr ),*) => { 20 #[cfg(feature = "log")] 21 { 22 use core::fmt::Write; 23 24 use {write, log}; 25 use log::internal::IntoCursor; 26 27 // Print the pool state. 28 let mut log = write::LogWriter::new(); 29 let _ = write!(log, "({:2}) {:10?} : ", $bk.id, log::internal::BlockLogger { 30 cur: $cur.clone().into_cursor(), 31 blocks: &$bk.pool, 32 }); 33 34 // Print the log message. 35 let _ = write!(log, $( $arg ),*); 36 let _ = writeln!(log, " (at {}:{})", file!(), line!()); 37 } 38 }; 39 } 40 41 /// Top secret place-holding module. 42 #[macro_use] 43 #[cfg(feature = "log")] 44 pub mod internal { 45 use prelude::*; 46 47 use core::fmt; 48 49 use core::cell::Cell; 50 use core::ops::Range; 51 52 /// A "cursor". 53 /// 54 /// Cursors represents a block or an interval in the log output. This trait is implemented for 55 /// various types that can represent a cursor. 56 pub trait Cursor { 57 /// Iteration at n. 58 /// 59 /// This is called in the logging loop. The cursor should then write, what it needs, to the 60 /// formatter if the underlying condition is true. 61 /// 62 /// For example, a plain position cursor will write `"|"` when `n == self.pos`. 63 // TODO: Use an iterator instead. 64 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result; 65 66 /// The after hook. 67 /// 68 /// This is runned when the loop is over. The aim is to e.g. catch up if the cursor wasn't 69 /// printed (i.e. is out of range). 70 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result; 71 } 72 73 /// Types that can be converted into a cursor. 74 pub trait IntoCursor { 75 /// The end result. 76 type Cursor: Cursor; 77 78 /// Convert this value into its equivalent cursor. 79 fn into_cursor(self) -> Self::Cursor; 80 } 81 82 /// A single-point cursor. 83 pub struct UniCursor { 84 /// The position where this cursor will be placed. 85 pos: usize, 86 /// Is this cursor printed? 87 /// 88 /// This is used for the after hook. 89 is_printed: Cell<bool>, 90 } 91 92 impl Cursor for UniCursor { 93 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 94 if self.pos == n { 95 self.is_printed.set(true); 96 write!(f, "|")?; 97 } 98 99 Ok(()) 100 } 101 102 fn after(&self, f: &mut fmt::Formatter) -> fmt::Result { 103 if !self.is_printed.get() { 104 write!(f, "…|")?; 105 } 106 107 Ok(()) 108 } 109 } 110 111 impl IntoCursor for usize { 112 type Cursor = UniCursor; 113 114 fn into_cursor(self) -> UniCursor { 115 UniCursor { 116 pos: self, 117 is_printed: Cell::new(false), 118 } 119 } 120 } 121 122 impl Cursor for () { 123 fn at(&self, _: &mut fmt::Formatter, _: usize) -> fmt::Result { Ok(()) } 124 125 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 126 } 127 128 impl IntoCursor for () { 129 type Cursor = (); 130 131 fn into_cursor(self) -> () { 132 () 133 } 134 } 135 136 /// A interval/range cursor. 137 /// 138 /// The start of the range is marked by `[` and the end by `]`. 139 pub struct RangeCursor { 140 /// The range of this cursor. 141 range: Range<usize>, 142 } 143 144 impl Cursor for RangeCursor { 145 fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result { 146 if self.range.start == n { 147 write!(f, "[")?; 148 } else if self.range.end == n { 149 write!(f, "]")?; 150 } 151 152 Ok(()) 153 } 154 155 fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } 156 } 157 158 impl IntoCursor for Range<usize> { 159 type Cursor = RangeCursor; 160 161 fn into_cursor(self) -> RangeCursor { 162 RangeCursor { 163 range: self, 164 } 165 } 166 } 167 168 /// A "block logger". 169 /// 170 /// This intend to show the structure of a block pool. The syntax used is like: 171 /// 172 /// ``` 173 /// xxx__|xx_ 174 /// ``` 175 /// 176 /// where `x` denotes an non-empty block. `_` denotes an empty block, with `|` representing the 177 /// cursor. 178 pub struct BlockLogger<'a, T> { 179 /// The cursor. 180 /// 181 /// This is where the `|` will be printed. 182 pub cur: T, 183 /// The blocks. 184 pub blocks: &'a [Block], 185 } 186 187 impl<'a, T: Cursor> fmt::Debug for BlockLogger<'a, T> { 188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 189 // TODO: Handle alignment etc. 190 191 for (n, i) in self.blocks.iter().enumerate() { 192 self.cur.at(f, n)?; 193 194 if i.is_empty() { 195 // Empty block. 196 write!(f, "_")?; 197 } else { 198 // Non-empty block. 199 write!(f, "x")?; 200 } 201 } 202 203 self.cur.after(f)?; 204 205 Ok(()) 206 } 207 } 208 } 209