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