hermit/
console.rs

1use core::task::Waker;
2use core::{fmt, mem};
3
4use heapless::Vec;
5use hermit_sync::{InterruptTicketMutex, Lazy};
6
7use crate::arch;
8
9const SERIAL_BUFFER_SIZE: usize = 256;
10
11pub(crate) struct Console {
12	pub inner: arch::kernel::Console,
13	buffer: Vec<u8, SERIAL_BUFFER_SIZE>,
14}
15
16impl Console {
17	fn new() -> Self {
18		Self {
19			inner: arch::kernel::Console::new(),
20			buffer: Vec::new(),
21		}
22	}
23
24	pub fn write(&mut self, buf: &[u8]) {
25		if SERIAL_BUFFER_SIZE - self.buffer.len() >= buf.len() {
26			// unwrap: we checked that buf fits in self.buffer
27			self.buffer.extend_from_slice(buf).unwrap();
28			if buf.contains(&b'\n') {
29				self.inner.write(&self.buffer);
30				self.buffer.clear();
31			}
32		} else {
33			self.inner.write(&self.buffer);
34			self.buffer.clear();
35			if buf.len() >= SERIAL_BUFFER_SIZE {
36				self.inner.write(buf);
37			} else {
38				// unwrap: we checked that buf fits in self.buffer
39				self.buffer.extend_from_slice(buf).unwrap();
40				if buf.contains(&b'\n') {
41					self.inner.write(&self.buffer);
42					self.buffer.clear();
43				}
44			}
45		}
46	}
47
48	pub fn read(&mut self) -> Option<u8> {
49		self.inner.read()
50	}
51
52	pub fn is_empty(&self) -> bool {
53		self.inner.is_empty()
54	}
55
56	pub fn register_waker(&mut self, waker: &Waker) {
57		self.inner.register_waker(waker);
58	}
59}
60
61/// A collection of methods that are required to format
62/// a message to Hermit's console.
63impl fmt::Write for Console {
64	/// Print a string of characters.
65	#[inline]
66	fn write_str(&mut self, s: &str) -> fmt::Result {
67		if !s.is_empty() {
68			self.write(s.as_bytes());
69		}
70
71		Ok(())
72	}
73}
74
75pub(crate) static CONSOLE: Lazy<InterruptTicketMutex<Console>> =
76	Lazy::new(|| InterruptTicketMutex::new(Console::new()));
77
78#[doc(hidden)]
79pub fn _print(args: fmt::Arguments<'_>) {
80	use fmt::Write;
81	CONSOLE.lock().write_fmt(args).unwrap();
82}
83
84#[doc(hidden)]
85pub fn _panic_print(args: fmt::Arguments<'_>) {
86	use fmt::Write;
87	let mut console = unsafe { CONSOLE.make_guard_unchecked() };
88	console.write_fmt(args).ok();
89	mem::forget(console);
90}
91
92#[cfg(all(test, not(target_os = "none")))]
93mod tests {
94	use super::*;
95
96	#[test]
97	fn test_console() {
98		println!("HelloWorld");
99	}
100}