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	/// Writes a buffer to the console.
25	/// The content is buffered until a newline is encountered or the internal buffer is full.
26	/// To force early output, use [`flush`](Self::flush).
27	pub fn write(&mut self, buf: &[u8]) {
28		if SERIAL_BUFFER_SIZE - self.buffer.len() >= buf.len() {
29			// unwrap: we checked that buf fits in self.buffer
30			self.buffer.extend_from_slice(buf).unwrap();
31			if buf.contains(&b'\n') {
32				self.flush();
33			}
34		} else {
35			self.inner.write(&self.buffer);
36			self.buffer.clear();
37			if buf.len() >= SERIAL_BUFFER_SIZE {
38				self.inner.write(buf);
39			} else {
40				// unwrap: we checked that buf fits in self.buffer
41				self.buffer.extend_from_slice(buf).unwrap();
42				if buf.contains(&b'\n') {
43					self.flush();
44				}
45			}
46		}
47	}
48
49	/// Immediately writes everything in the internal buffer to the output.
50	pub fn flush(&mut self) {
51		self.inner.write(&self.buffer);
52		self.buffer.clear();
53	}
54
55	pub fn read(&mut self) -> Option<u8> {
56		self.inner.read()
57	}
58
59	pub fn is_empty(&self) -> bool {
60		self.inner.is_empty()
61	}
62
63	pub fn register_waker(&mut self, waker: &Waker) {
64		self.inner.register_waker(waker);
65	}
66}
67
68/// A collection of methods that are required to format
69/// a message to Hermit's console.
70impl fmt::Write for Console {
71	/// Print a string of characters.
72	#[inline]
73	fn write_str(&mut self, s: &str) -> fmt::Result {
74		if !s.is_empty() {
75			self.write(s.as_bytes());
76		}
77
78		Ok(())
79	}
80}
81
82pub(crate) static CONSOLE: Lazy<InterruptTicketMutex<Console>> =
83	Lazy::new(|| InterruptTicketMutex::new(Console::new()));
84
85#[doc(hidden)]
86pub fn _print(args: fmt::Arguments<'_>) {
87	use fmt::Write;
88	CONSOLE.lock().write_fmt(args).unwrap();
89}
90
91#[doc(hidden)]
92pub fn _panic_print(args: fmt::Arguments<'_>) {
93	use fmt::Write;
94	let mut console = unsafe { CONSOLE.make_guard_unchecked() };
95	console.write_fmt(args).ok();
96	mem::forget(console);
97}
98
99#[cfg(all(test, not(target_os = "none")))]
100mod tests {
101	use super::*;
102
103	#[test]
104	fn test_console() {
105		println!("HelloWorld");
106	}
107}