Nothing to see here, move along
1use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
2
3use lancer_core::ipc::{MAX_IPC_BYTES, pack_bytes};
4
5static STDOUT_SLOT: AtomicU64 = AtomicU64::new(u64::MAX);
6static DEBUG_PRINT_ENABLED: AtomicBool = AtomicBool::new(true);
7
8pub fn set_debug_print_enabled(enabled: bool) {
9 DEBUG_PRINT_ENABLED.store(enabled, Ordering::Relaxed);
10}
11
12pub fn debug_print_enabled() -> bool {
13 DEBUG_PRINT_ENABLED.load(Ordering::Relaxed)
14}
15
16const PARENT_NOTIF_SLOT: u64 = 5;
17const NOTIFY_BIT_CHILD_IPC: u64 = 0x200;
18
19pub fn set_stdout_slot(slot: u64) {
20 STDOUT_SLOT.store(slot, Ordering::Relaxed);
21}
22
23pub fn signal_parent() {
24 let _ = crate::syscall::notify_signal(PARENT_NOTIF_SLOT, NOTIFY_BIT_CHILD_IPC);
25}
26
27pub struct Stdout;
28
29impl core::fmt::Write for Stdout {
30 fn write_str(&mut self, s: &str) -> core::fmt::Result {
31 if DEBUG_PRINT_ENABLED.load(Ordering::Relaxed) {
32 crate::syscall::debug_print(s);
33 }
34 let slot = STDOUT_SLOT.load(Ordering::Relaxed);
35 match slot {
36 u64::MAX => {}
37 _ => s.as_bytes().chunks(MAX_IPC_BYTES).for_each(|chunk| {
38 let msg = pack_bytes(chunk);
39 let _ = crate::syscall::send(slot, msg);
40 }),
41 }
42 Ok(())
43 }
44}
45
46pub fn write_bytes(data: &[u8]) {
47 let debug = DEBUG_PRINT_ENABLED.load(Ordering::Relaxed);
48 let slot = STDOUT_SLOT.load(Ordering::Relaxed);
49 data.chunks(MAX_IPC_BYTES).for_each(|chunk| {
50 if debug
51 && let Ok(s) = core::str::from_utf8(chunk)
52 {
53 crate::syscall::debug_print(s);
54 }
55 match slot {
56 u64::MAX => {}
57 _ => {
58 let msg = pack_bytes(chunk);
59 let _ = crate::syscall::send(slot, msg);
60 }
61 }
62 });
63}
64
65const LOG_BUF_LEN: usize = 256;
66
67pub struct LogBuf {
68 buf: [u8; LOG_BUF_LEN],
69 pos: usize,
70}
71
72impl LogBuf {
73 pub const fn new() -> Self {
74 Self {
75 buf: [0u8; LOG_BUF_LEN],
76 pos: 0,
77 }
78 }
79
80 pub fn as_str(&self) -> &str {
81 unsafe { core::str::from_utf8_unchecked(&self.buf[..self.pos]) }
82 }
83}
84
85impl Default for LogBuf {
86 fn default() -> Self {
87 Self::new()
88 }
89}
90
91impl core::fmt::Write for LogBuf {
92 fn write_str(&mut self, s: &str) -> core::fmt::Result {
93 let bytes = s.as_bytes();
94 let copy_len = bytes.len().min(LOG_BUF_LEN - self.pos);
95 self.buf[self.pos..self.pos + copy_len].copy_from_slice(&bytes[..copy_len]);
96 self.pos += copy_len;
97 Ok(())
98 }
99}
100
101#[macro_export]
102macro_rules! log {
103 ($domain:ident, error, $($arg:tt)*) => {{
104 $crate::io::user_log(lancer_log::Severity::Error, format_args!($($arg)*));
105 }};
106 ($domain:ident, warn, $($arg:tt)*) => {{
107 $crate::io::user_log(lancer_log::Severity::Warn, format_args!($($arg)*));
108 }};
109 ($domain:ident, $($arg:tt)*) => {{
110 $crate::io::user_log(lancer_log::Severity::Info, format_args!($($arg)*));
111 }};
112}
113
114pub fn user_log(severity: lancer_log::Severity, message: core::fmt::Arguments<'_>) {
115 use core::fmt::Write;
116 let mut buf = LogBuf::new();
117 let _ = write!(buf, "{}", message);
118 crate::syscall::log(severity.as_u8(), buf.as_str());
119}
120
121#[macro_export]
122macro_rules! show {
123 ($domain:ident, error, $($arg:tt)*) => {{
124 $crate::io::user_show(
125 stringify!($domain),
126 lancer_log::Severity::Error,
127 format_args!($($arg)*),
128 );
129 }};
130 ($domain:ident, warn, $($arg:tt)*) => {{
131 $crate::io::user_show(
132 stringify!($domain),
133 lancer_log::Severity::Warn,
134 format_args!($($arg)*),
135 );
136 }};
137 ($domain:ident, $($arg:tt)*) => {{
138 $crate::io::user_show(
139 stringify!($domain),
140 lancer_log::Severity::Info,
141 format_args!($($arg)*),
142 );
143 }};
144}
145
146pub fn stdout_ipc(s: &str) {
147 let slot = STDOUT_SLOT.load(Ordering::Relaxed);
148 match slot {
149 u64::MAX => {}
150 _ => s.as_bytes().chunks(MAX_IPC_BYTES).for_each(|chunk| {
151 let msg = pack_bytes(chunk);
152 let _ = crate::syscall::send(slot, msg);
153 }),
154 }
155}
156
157const GLASS_BIT: u8 = 0x80;
158
159pub fn user_show(domain: &str, severity: lancer_log::Severity, message: core::fmt::Arguments<'_>) {
160 use core::fmt::Write;
161 let mut plain = LogBuf::new();
162 let _ = write!(plain, "{}", message);
163 crate::syscall::log(severity.as_u8() | GLASS_BIT, plain.as_str());
164 let mut formatted = LogBuf::new();
165 let _ = lancer_log::format::write_gutter(&mut formatted, domain, severity, message, USER_SHOW_GUTTER);
166 let _ = formatted.write_str("\n");
167 stdout_ipc(formatted.as_str());
168}
169
170const USER_SHOW_GUTTER: usize = 13;
171
172#[macro_export]
173macro_rules! print {
174 ($($arg:tt)*) => {{
175 use core::fmt::Write;
176 let _ = write!($crate::io::Stdout, $($arg)*);
177 }};
178}
179
180#[macro_export]
181macro_rules! println {
182 () => { $crate::print!("\n") };
183 ($($arg:tt)*) => {{
184 use core::fmt::Write;
185 let _ = writeln!($crate::io::Stdout, $($arg)*);
186 }};
187}