#![no_std]
extern crate alloc;
use core::fmt::Arguments;
use alloc::format;
use log::{Level, LevelFilter, Metadata, Record};
use psp::sys::*;
#[derive(Copy, Clone)]
pub enum OutputStream {
StdOut,
StdErr,
}
pub struct PspLoggerConfig {
error_stream: OutputStream,
warn_stream: OutputStream,
info_stream: OutputStream,
debug_stream: OutputStream,
trace_stream: OutputStream,
level_filter: LevelFilter,
}
pub struct PspLogger {}
static LOGGER: PspLogger = PspLogger {};
static LOGGER_CONF: spin::Once<PspLoggerConfig> = spin::Once::new();
unsafe fn psp_write(stream: OutputStream, args: &Arguments) {
let fh = match stream {
OutputStream::StdErr => sceKernelStderr(),
OutputStream::StdOut => sceKernelStdout(),
};
let msg = alloc::fmt::format(*args);
let msg = format!("{}\n\0", msg);
sceIoWrite(fh, msg.as_ptr() as _, msg.len());
}
impl log::Log for PspLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= LOGGER_CONF.get().unwrap().level_filter
}
fn log(&self, record: &Record) {
let output = LOGGER_CONF
.get()
.unwrap()
.get_stream(record.metadata().level());
if self.enabled(record.metadata()) {
unsafe { psp_write(output, record.args()) }
}
}
fn flush(&self) {}
}
impl PspLogger {
pub fn init(config: PspLoggerConfig) -> Result<(), log::SetLoggerError> {
let level_filter = config.level_filter;
LOGGER_CONF.call_once(|| config);
log::set_logger(&LOGGER).map(|()| log::set_max_level(level_filter))
}
}
impl PspLoggerConfig {
pub fn new(level_filter: LevelFilter) -> Self {
PspLoggerConfig {
error_stream: OutputStream::StdErr,
warn_stream: OutputStream::StdErr,
info_stream: OutputStream::StdErr,
debug_stream: OutputStream::StdErr,
trace_stream: OutputStream::StdErr,
level_filter,
}
}
pub fn with_error_stream(mut self, stream: OutputStream) -> Self {
self.error_stream = stream;
self
}
pub fn with_warn_stream(mut self, stream: OutputStream) -> Self {
self.warn_stream = stream;
self
}
pub fn with_info_stream(mut self, stream: OutputStream) -> Self {
self.info_stream = stream;
self
}
pub fn with_debug_stream(mut self, stream: OutputStream) -> Self {
self.debug_stream = stream;
self
}
pub fn with_trace_stream(mut self, stream: OutputStream) -> Self {
self.trace_stream = stream;
self
}
fn get_stream(&self, level: Level) -> OutputStream {
match level {
Level::Error => self.error_stream,
Level::Warn => self.warn_stream,
Level::Info => self.info_stream,
Level::Debug => self.debug_stream,
Level::Trace => self.trace_stream,
}
}
}