1#![no_std]
10#![deny(warnings, missing_docs)]
11
12use core::{
13 fmt::{self, Write},
14 str::FromStr,
15};
16use spin::Once;
17
18pub extern crate log;
20
21pub trait Console: Sync {
23 fn put_char(&self, c: u8);
25
26 #[inline]
30 fn put_str(&self, s: &str) {
31 for c in s.bytes() {
32 self.put_char(c);
33 }
34 }
35}
36
37static CONSOLE: Once<&'static dyn Console> = Once::new();
42
43const BUFFER_SIZE: usize = 64;
45
46struct PrintBuffer {
51 buffer: [u8; BUFFER_SIZE],
52 pos: usize,
53}
54
55impl PrintBuffer {
56 const fn new() -> Self {
58 Self {
59 buffer: [0u8; BUFFER_SIZE],
60 pos: 0,
61 }
62 }
63
64 fn flush(&mut self) {
66 if self.pos > 0 {
67 if let Some(console) = CONSOLE.get() {
68 let s = unsafe { core::str::from_utf8_unchecked(&self.buffer[..self.pos]) };
70 console.put_str(s);
71 }
72 self.pos = 0;
73 }
74 }
75
76 fn write(&mut self, s: &str) {
78 let bytes = s.as_bytes();
79 let mut offset = 0;
80
81 while offset < bytes.len() {
82 let remaining_buffer = BUFFER_SIZE - self.pos;
83 let remaining_input = bytes.len() - offset;
84 let to_copy = remaining_buffer.min(remaining_input);
85
86 self.buffer[self.pos..self.pos + to_copy]
87 .copy_from_slice(&bytes[offset..offset + to_copy]);
88 self.pos += to_copy;
89 offset += to_copy;
90
91 if self.pos == BUFFER_SIZE {
93 self.flush();
94 }
95 }
96 }
97}
98
99impl Write for PrintBuffer {
100 fn write_str(&mut self, s: &str) -> fmt::Result {
101 self.write(s);
102 Ok(())
103 }
104}
105
106pub fn init_console(console: &'static dyn Console) {
108 CONSOLE.call_once(|| console);
110 log::set_logger(&Logger).unwrap();
111}
112
113pub fn set_log_level(env: Option<&str>) {
115 use log::LevelFilter as Lv;
116 log::set_max_level(env.and_then(|s| Lv::from_str(s).ok()).unwrap_or(Lv::Trace));
117}
118
119pub fn test_log() {
121 println!(
122 r"
123 ______ __
124 / ____/___ ____ _________ / /__
125 / / / __ \/ __ \/ ___/ __ \/ / _ \
126/ /___/ /_/ / / / (__ ) /_/ / / __/
127\____/\____/_/ /_/____/\____/_/\___/
128===================================="
129 );
130 log::trace!("LOG TEST >> Hello, world!");
131 log::debug!("LOG TEST >> Hello, world!");
132 log::info!("LOG TEST >> Hello, world!");
133 log::warn!("LOG TEST >> Hello, world!");
134 log::error!("LOG TEST >> Hello, world!");
135 println!();
136}
137
138#[doc(hidden)]
143#[inline]
144pub fn _print(args: fmt::Arguments) {
145 let mut buffer = PrintBuffer::new();
147 buffer.write_fmt(args).unwrap();
148 buffer.flush();
149}
150
151#[macro_export]
153macro_rules! print {
154 ($($arg:tt)*) => {
155 $crate::_print(core::format_args!($($arg)*));
156 }
157}
158
159#[macro_export]
161macro_rules! println {
162 () => ($crate::print!("\n"));
163 ($($arg:tt)*) => {{
164 $crate::_print(core::format_args!($($arg)*));
165 $crate::println!();
166 }}
167}
168
169struct Logger;
171
172impl Write for Logger {
174 #[inline]
175 fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
176 let _ = CONSOLE.get().unwrap().put_str(s);
177 Ok(())
178 }
179}
180
181impl log::Log for Logger {
183 #[inline]
184 fn enabled(&self, _metadata: &log::Metadata) -> bool {
185 true
186 }
187
188 #[inline]
189 fn log(&self, record: &log::Record) {
190 use log::Level::*;
191 let color_code: u8 = match record.level() {
193 Error => 31,
194 Warn => 93,
195 Info => 34,
196 Debug => 32,
197 Trace => 90,
198 };
199 println!(
200 "\x1b[{color_code}m[{:>5}] {}\x1b[0m",
201 record.level(),
202 record.args(),
203 );
204 }
205
206 fn flush(&self) {}
207}