tiny_std/unix/
print.rs

1//! Synchronized printing to stdout and stderr
2use crate::sync::Mutex;
3
4pub static __STDOUT_LOCK: Mutex<()> = Mutex::new(());
5pub static __STDERR_LOCK: Mutex<()> = Mutex::new(());
6
7use rusl::platform::Fd;
8
9/// Corresponds to std's `print!`-macro
10#[macro_export]
11macro_rules! print {
12    ($($arg:tt)*) => {
13        {
14            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDOUT_LOCK.lock();
15            let mut __tiny_std_unix_print_writer = $crate::unix::print::__STDOUT_WRITER;
16            let _ = core::fmt::Write::write_fmt(&mut __tiny_std_unix_print_writer, format_args!($($arg)*));
17        }
18    }
19}
20
21/// Corresponds to std's `println!`-macro
22#[macro_export]
23macro_rules! println {
24    () => {
25        {
26            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDOUT_LOCK.lock();
27            let __tiny_std_unix_print_writer = $crate::unix::print::__STDOUT_WRITER;
28            let _ = __tiny_std_unix_print_writer.__write_newline();
29        }
30    };
31    ($($arg:tt)*) => {
32        {
33            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDOUT_LOCK.lock();
34            let mut __tiny_std_unix_print_writer = $crate::unix::print::__STDOUT_WRITER;
35            let _ = core::fmt::Write::write_fmt(&mut __tiny_std_unix_print_writer, format_args!($($arg)*));
36            let _ = __tiny_std_unix_print_writer.__write_newline();
37        }
38    }
39}
40
41/// Corresponds to std's `eprint!`-macro
42#[macro_export]
43macro_rules! eprint {
44    ($($arg:tt)*) => {
45        {
46            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDERR_LOCK.lock();
47            let mut __tiny_std_unix_print_writer = $crate::unix::print::__STDERR_WRITER;
48            let _ = core::fmt::Write::write_fmt(&mut __tiny_std_unix_print_writer, format_args!($($arg)*));
49        }
50    }
51}
52
53/// Corresponds to std's `eprintln!`-macro
54#[macro_export]
55macro_rules! eprintln {
56    () => {
57        {
58            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDERR_LOCK.lock();
59            let __tiny_std_unix_print_writer = $crate::unix::print::__STDERR_WRITER;
60            let _ = __tiny_std_unix_print_writer.__write_newline();
61        }
62    };
63    ($($arg:tt)*) => {
64        {
65            let __tiny_std_unix_print_writer_guard = $crate::unix::print::__STDERR_LOCK.lock();
66            let mut __tiny_std_unix_print_writer = $crate::unix::print::__STDERR_WRITER;
67            let _ = core::fmt::Write::write_fmt(&mut __tiny_std_unix_print_writer, format_args!($($arg)*));
68            let _ = __tiny_std_unix_print_writer.__write_newline();
69        }
70    }
71}
72
73/// Corresponds to std's `dbg!`-macro
74#[macro_export]
75macro_rules! dbg {
76    () => {
77        $crate::eprintln!("[{}:{}]", core::file!(), core::line!())
78    };
79    ($val:expr $(,)?) => {
80        match $val {
81            tmp => {
82                $crate::eprintln!("[{}:{}] {} = {:#?}",
83                    core::file!(), core::line!(), core::stringify!($val), &tmp);
84                tmp
85            }
86        }
87    };
88    ($($val:expr),+ $(,)?) => {
89        ($($crate::dbg!($val)),+,)
90    };
91}
92
93fn try_print(fd: Fd, msg: &str) -> core::fmt::Result {
94    let buf = msg.as_bytes();
95    let len = buf.len();
96    let mut flushed = 0;
97    loop {
98        let res = rusl::unistd::write(fd, &buf[flushed..]).map_err(|_e| core::fmt::Error)?;
99        match res.cmp(&0) {
100            core::cmp::Ordering::Less => return Err(core::fmt::Error),
101            core::cmp::Ordering::Equal => return Ok(()),
102            core::cmp::Ordering::Greater => {
103                // Greater than zero
104                flushed += res as usize;
105                if flushed >= len {
106                    return Ok(());
107                }
108            }
109        }
110    }
111}
112
113pub struct __UnixWriter(Fd);
114
115pub const __STDOUT_WRITER: __UnixWriter = __UnixWriter(rusl::platform::STDOUT);
116pub const __STDERR_WRITER: __UnixWriter = __UnixWriter(rusl::platform::STDERR);
117impl __UnixWriter {
118    /// # Errors
119    /// Will return an error if the underlying syscall fails
120    pub fn __write_newline(&self) -> core::fmt::Result {
121        try_print(self.0, "\n")
122    }
123}
124
125impl core::fmt::Write for __UnixWriter {
126    #[inline]
127    fn write_str(&mut self, s: &str) -> core::fmt::Result {
128        try_print(self.0, s)
129    }
130}
131
132#[cfg(test)]
133mod tests {
134
135    #[test]
136    fn test_prints() {
137        print!("-- First");
138        print!("My first");
139        print!(" two messages");
140        print!(" were cutoff but it's fine");
141        println!();
142        println!("-- Second\nHello there {}", "me");
143    }
144
145    #[test]
146    fn test_eprints() {
147        eprintln!("-- First");
148        eprint!("My first");
149        eprint!(" two messages");
150        eprint!(" were cutoff but it's fine");
151        eprintln!();
152        eprintln!("-- Second\nHello there {}", "me");
153    }
154
155    #[test]
156    fn test_dbgs() {
157        dbg!();
158        let val = 5;
159        let res = dbg!(val) - 5;
160        assert_eq!(0, res);
161    }
162}