use crate::proto::console::text::Output;
use core::fmt::{self, Write};
use core::ptr::NonNull;
pub struct Logger {
writer: Option<NonNull<Output<'static>>>,
}
impl Logger {
pub unsafe fn new(output: &mut Output) -> Self {
Logger {
writer: NonNull::new(output as *const _ as *mut _),
}
}
pub fn disable(&mut self) {
self.writer = None;
}
}
impl<'boot> log::Log for Logger {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
self.writer.is_some()
}
fn log(&self, record: &log::Record) {
if let Some(mut ptr) = self.writer {
let writer = unsafe { ptr.as_mut() };
let result = DecoratedLog::write(
writer,
record.level(),
record.args(),
record.file().unwrap_or("<unknown file>"),
record.line().unwrap_or(0),
);
if !cfg!(feature = "ignore-logger-errors") {
result.unwrap()
}
}
}
fn flush(&self) {
}
}
unsafe impl Sync for Logger {}
unsafe impl Send for Logger {}
struct DecoratedLog<'writer, 'a, W: fmt::Write> {
writer: &'writer mut W,
log_level: log::Level,
at_line_start: bool,
file: &'a str,
line: u32,
}
impl<'writer, 'a, W: fmt::Write> DecoratedLog<'writer, 'a, W> {
fn write(
writer: &'writer mut W,
log_level: log::Level,
args: &fmt::Arguments,
file: &'a str,
line: u32,
) -> fmt::Result {
let mut decorated_writer = Self {
writer,
log_level,
at_line_start: true,
file,
line,
};
writeln!(decorated_writer, "{}", *args)
}
}
impl<'writer, 'a, W: fmt::Write> fmt::Write for DecoratedLog<'writer, 'a, W> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let mut lines = s.lines();
let first = lines.next().unwrap_or("");
if self.at_line_start {
write!(
self.writer,
"[{:>5}]: {:>12}@{:03}: ",
self.log_level, self.file, self.line
)?;
self.at_line_start = false;
}
write!(self.writer, "{}", first)?;
for line in lines {
write!(self.writer, "\n{}: {}", self.log_level, line)?;
}
if let Some('\n') = s.chars().next_back() {
writeln!(self.writer)?;
self.at_line_start = true;
}
Ok(())
}
}