#![no_std]
#![deny(warnings, missing_docs)]
use core::{
fmt::{self, Write},
str::FromStr,
};
use spin::Once;
pub extern crate log;
pub trait Console: Sync {
fn put_char(&self, c: u8);
#[inline]
fn put_str(&self, s: &str) {
for c in s.bytes() {
self.put_char(c);
}
}
}
static CONSOLE: Once<&'static dyn Console> = Once::new();
const BUFFER_SIZE: usize = 64;
struct PrintBuffer {
buffer: [u8; BUFFER_SIZE],
pos: usize,
}
impl PrintBuffer {
const fn new() -> Self {
Self {
buffer: [0u8; BUFFER_SIZE],
pos: 0,
}
}
fn flush(&mut self) {
if self.pos > 0 {
if let Some(console) = CONSOLE.get() {
let s = unsafe { core::str::from_utf8_unchecked(&self.buffer[..self.pos]) };
console.put_str(s);
}
self.pos = 0;
}
}
fn write(&mut self, s: &str) {
let bytes = s.as_bytes();
let mut offset = 0;
while offset < bytes.len() {
let remaining_buffer = BUFFER_SIZE - self.pos;
let remaining_input = bytes.len() - offset;
let to_copy = remaining_buffer.min(remaining_input);
self.buffer[self.pos..self.pos + to_copy]
.copy_from_slice(&bytes[offset..offset + to_copy]);
self.pos += to_copy;
offset += to_copy;
if self.pos == BUFFER_SIZE {
self.flush();
}
}
}
}
impl Write for PrintBuffer {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write(s);
Ok(())
}
}
pub fn init_console(console: &'static dyn Console) {
CONSOLE.call_once(|| console);
log::set_logger(&Logger).unwrap();
}
pub fn set_log_level(env: Option<&str>) {
use log::LevelFilter as Lv;
log::set_max_level(env.and_then(|s| Lv::from_str(s).ok()).unwrap_or(Lv::Trace));
}
pub fn test_log() {
println!(
r"
______ __
/ ____/___ ____ _________ / /__
/ / / __ \/ __ \/ ___/ __ \/ / _ \
/ /___/ /_/ / / / (__ ) /_/ / / __/
\____/\____/_/ /_/____/\____/_/\___/
===================================="
);
log::trace!("LOG TEST >> Hello, world!");
log::debug!("LOG TEST >> Hello, world!");
log::info!("LOG TEST >> Hello, world!");
log::warn!("LOG TEST >> Hello, world!");
log::error!("LOG TEST >> Hello, world!");
println!();
}
#[doc(hidden)]
#[inline]
pub fn _print(args: fmt::Arguments) {
let mut buffer = PrintBuffer::new();
buffer.write_fmt(args).unwrap();
buffer.flush();
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => {
$crate::_print(core::format_args!($($arg)*));
}
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => {{
$crate::_print(core::format_args!($($arg)*));
$crate::println!();
}}
}
struct Logger;
impl Write for Logger {
#[inline]
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
let _ = CONSOLE.get().unwrap().put_str(s);
Ok(())
}
}
impl log::Log for Logger {
#[inline]
fn enabled(&self, _metadata: &log::Metadata) -> bool {
true
}
#[inline]
fn log(&self, record: &log::Record) {
use log::Level::*;
let color_code: u8 = match record.level() {
Error => 31,
Warn => 93,
Info => 34,
Debug => 32,
Trace => 90,
};
println!(
"\x1b[{color_code}m[{:>5}] {}\x1b[0m",
record.level(),
record.args(),
);
}
fn flush(&self) {}
}