kernel/library/std/print.rs
1//! # Print Macros and UART Handling
2//!
3//! This module provides functionality for formatted printing through a UART device.
4//! It defines the core printing macros (`print!` and `println!`) used throughout the kernel,
5//! along with the necessary infrastructure to handle UART output.
6//!
7//! ## Examples
8//!
9//! ```
10//! println!("Hello, world!");
11//! println!("Value: {}", 42);
12//! print!("No newline here");
13//! ```
14//!
15//! ## Implementation Details
16//!
17//! The module initializes a UART writer lazily when first used and provides the
18//! core implementation of the `Write` trait for the UART device. It automatically
19//! handles CR+LF conversion for newlines.
20
21/// Implements core printing functionality by writing formatted text to the UART.
22/// This function is called by the `print!` macro and handles lazy initialization
23/// of the UART writer if it doesn't exist.
24///
25/// # Arguments
26///
27/// * `args` - Formatted arguments to print
28///
29/// # Note
30///
31/// This function is not meant to be called directly. Use the `print!` or
32/// `println!` macros instead.
33
34/// Wraps a UART device to implement the `core::fmt::Write` trait.
35///
36/// This allows the UART to be used with the standard formatting macros.
37use core::fmt;
38use core::fmt::Write;
39
40use crate::device::manager::DeviceManager;
41use crate::device::char::CharDevice;
42use crate::early_println;
43
44#[macro_export]
45macro_rules! print {
46 ($($arg:tt)*) => ($crate::library::std::print::_print(format_args!($($arg)*)));
47}
48
49#[macro_export]
50macro_rules! println {
51 ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
52 ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
53}
54
55pub fn _print(args: fmt::Arguments) {
56 let manager = DeviceManager::get_manager();
57
58 // Try to find a character device (UART)
59 if let Some(device_id) = manager.get_first_device_by_type(crate::device::DeviceType::Char) {
60 if let Some(char_device) = manager.get_device(device_id).unwrap().as_char_device() {
61 // Use CharDevice trait methods to write
62 struct CharDeviceWriter<'a>(&'a dyn CharDevice);
63
64 impl<'a> fmt::Write for CharDeviceWriter<'a> {
65 fn write_str(&mut self, s: &str) -> fmt::Result {
66 for byte in s.bytes() {
67 if self.0.write_byte(byte).is_err() {
68 return Err(fmt::Error);
69 }
70 }
71 Ok(())
72 }
73 }
74
75 let mut writer = CharDeviceWriter(char_device);
76 if writer.write_fmt(args).is_ok() {
77 return;
78 }
79 }
80 }
81
82 // Fallback to early_println if no character device found
83 early_println!("[print] No character device found, using early console");
84}