hermit/
console.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use core::task::Waker;
use core::{fmt, mem};

use heapless::Vec;
use hermit_sync::{InterruptTicketMutex, Lazy};

use crate::arch;

const SERIAL_BUFFER_SIZE: usize = 256;

pub(crate) struct Console {
	pub inner: arch::kernel::Console,
	buffer: Vec<u8, SERIAL_BUFFER_SIZE>,
}

impl Console {
	fn new() -> Self {
		Self {
			inner: arch::kernel::Console::new(),
			buffer: Vec::new(),
		}
	}

	pub fn write(&mut self, buf: &[u8]) {
		if SERIAL_BUFFER_SIZE - self.buffer.len() >= buf.len() {
			// unwrap: we checked that buf fits in self.buffer
			self.buffer.extend_from_slice(buf).unwrap();
			if buf.contains(&b'\n') {
				self.inner.write(&self.buffer);
				self.buffer.clear();
			}
		} else {
			self.inner.write(&self.buffer);
			self.buffer.clear();
			if buf.len() >= SERIAL_BUFFER_SIZE {
				self.inner.write(buf);
			} else {
				// unwrap: we checked that buf fits in self.buffer
				self.buffer.extend_from_slice(buf).unwrap();
				if buf.contains(&b'\n') {
					self.inner.write(&self.buffer);
					self.buffer.clear();
				}
			}
		}
	}

	pub fn read(&mut self) -> Option<u8> {
		self.inner.read()
	}

	pub fn is_empty(&self) -> bool {
		self.inner.is_empty()
	}

	pub fn register_waker(&mut self, waker: &Waker) {
		self.inner.register_waker(waker);
	}
}

/// A collection of methods that are required to format
/// a message to Hermit's console.
impl fmt::Write for Console {
	/// Print a string of characters.
	#[inline]
	fn write_str(&mut self, s: &str) -> fmt::Result {
		if !s.is_empty() {
			self.write(s.as_bytes());
		}

		Ok(())
	}
}

pub(crate) static CONSOLE: Lazy<InterruptTicketMutex<Console>> =
	Lazy::new(|| InterruptTicketMutex::new(Console::new()));

#[doc(hidden)]
pub fn _print(args: fmt::Arguments<'_>) {
	use fmt::Write;
	CONSOLE.lock().write_fmt(args).unwrap();
}

#[doc(hidden)]
pub fn _panic_print(args: fmt::Arguments<'_>) {
	use fmt::Write;
	let mut console = unsafe { CONSOLE.make_guard_unchecked() };
	console.write_fmt(args).ok();
	mem::forget(console);
}

#[cfg(all(test, not(target_os = "none")))]
mod tests {
	use super::*;

	#[test]
	fn test_console() {
		println!("HelloWorld");
	}
}