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}