#![doc(hidden)]
use crate::std::AsCStr;
use crate::sys::kernel;
use core::fmt;
pub trait ImplsAsCStr {
fn impls_as_cstr(&self) -> Option<&[u8]>;
}
impl<const N: usize> ImplsAsCStr for [u8; N] {
fn impls_as_cstr(&self) -> Option<&[u8]> {
Some(self.as_ref())
}
}
impl ImplsAsCStr for &[u8] {
fn impls_as_cstr(&self) -> Option<&[u8]> {
Some(self.as_ref())
}
}
impl ImplsAsCStr for &str {
fn impls_as_cstr(&self) -> Option<&[u8]> {
Some(self.as_ref())
}
}
impl<T> ImplsAsCStr for T {
default fn impls_as_cstr(&self) -> Option<&[u8]> {
None
}
}
pub struct TTY;
#[macro_export]
macro_rules! printf {
($msg:expr $(,$args:expr)*) => {
$crate::printf_impl!($msg $(,$args)*);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! printf_impl {
($msg:expr $(,$args:expr)*) => {
{
use $crate::std::AsCStr;
use $crate::sys::tty::ImplsAsCStr;
$msg.as_cstr(|cs| {
$crate::printf_impl!(@parse $($args,)*; {cs.as_ptr()});
});
}
};
(@parse $msg:expr $(,$args:expr)* $(,)?; {$($acc:tt)*}) => {
{
if let Some(s) = $msg.impls_as_cstr() {
s.as_cstr(|cs| {
$crate::printf_impl!(@parse $($args,)*; {$($acc)*, cs.as_ptr()});
})
} else {
$crate::printf_impl!(@parse $($args,)*; {$($acc)*,$msg});
}
}
};
(@parse; {$($acc:tt)*}) => {
unsafe {
$crate::sys::kernel::psx_printf($($acc)*)
}
};
}
#[macro_export]
macro_rules! print {
($($args:tt)*) => {
{
use $crate::sys::tty::TTY;
<TTY as core::fmt::Write>::write_fmt(&mut TTY, format_args!($($args)*)).ok();
}
};
}
#[macro_export]
macro_rules! println {
($($args:tt)*) => {
{
use $crate::sys::tty::TTY;
<TTY as core::fmt::Write>::write_fmt(&mut TTY, format_args!($($args)*)).ok();
#[allow(unused_unsafe)]
unsafe {
$crate::sys::kernel::psx_printf(b"\n\0".as_ptr() as *const i8);
}
}
};
}
impl fmt::Write for TTY {
fn write_str(&mut self, msg: &str) -> fmt::Result {
msg.as_cstr(|cstr|
unsafe {
kernel::psx_printf(b"%s\0".as_ptr() as *const i8, cstr.as_ptr());
});
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test_case]
fn impls_as_cstr() {
let array: [u8; 0] = [];
let array_ref: &[u8; 0] = b"";
let slice: &[u8] = &array_ref[..];
let str_ref: &str = "";
assert!(array.impls_as_cstr().is_some());
assert!(array_ref.impls_as_cstr().is_some());
assert!(slice.impls_as_cstr().is_some());
assert!(str_ref.impls_as_cstr().is_some());
assert!(0xdeadbeefu32.impls_as_cstr().is_none());
}
}