pros_core/io/
mod.rs

1//! Std-like I/O macros and types for use in pros.
2//!
3//! Implements `println!`, `eprintln!` and `dbg!` on top of the `pros_sys` crate without requiring
4//! the use of an allocator. (Modified version of `libc_print` crate)
5//!
6//! Allows you to use these macros in a #!\[no_std\] context, or in a situation where the
7//! traditional Rust streams might not be available (ie: at process shutdown time).
8//!
9//! ## Usage
10//!
11//! Exactly as you'd use `println!`, `eprintln!` and `dbg!`.
12//!
13//! ```rust
14//! # use pros::io::*;
15//! // Use the default ``-prefixed macros:
16//! # fn test1()
17//! # {
18//! println!("Hello {}!", "stdout");
19//! eprintln!("Hello {}!", "stderr");
20//! let a = 2;
21//! let b = dbg!(a * 2) + 1;
22//! assert_eq!(b, 5);
23//! # }
24//! ```
25//!
26//! Or you can import aliases to `std` names:
27//!
28//! ```rust
29//! use pros::io::{println, eprintln, dbg};
30//!
31//! # fn test2()
32//! # {
33//! println!("Hello {}!", "stdout");
34//! eprintln!("Hello {}!", "stderr");
35//! let a = 2;
36//! let b = dbg!(a * 2) + 1;
37//! assert_eq!(b, 5);
38//! # }
39//! ```
40
41// libc_print is licensed under the MIT License:
42
43// Copyright (c) 2023 Matt Mastracci and contributors
44
45// Permission is hereby granted, free of charge, to any person obtaining a copy
46// of this software and associated documentation files (the "Software"), to deal
47// in the Software without restriction, including without limitation the rights
48// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49// copies of the Software, and to permit persons to whom the Software is
50// furnished to do so, subject to the following conditions:
51
52// The above copyright notice and this permission notice shall be included in all
53// copies or substantial portions of the Software.
54
55// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
61// SOFTWARE.
62#[allow(unused_imports)]
63use core::{convert::TryFrom, file, line, stringify};
64
65pub use no_std_io::io::*;
66
67pub use crate::{dbg, eprint, eprintln, print, println};
68
69#[doc(hidden)]
70#[allow(missing_debug_implementations)]
71pub struct __SerialWriter(i32);
72
73impl core::fmt::Write for __SerialWriter {
74    #[inline]
75    fn write_str(&mut self, s: &str) -> core::fmt::Result {
76        __println(self.0, s)
77    }
78}
79
80impl __SerialWriter {
81    #[inline]
82    pub const fn new(err: bool) -> __SerialWriter {
83        __SerialWriter(if err { 2 } else { 1 })
84    }
85
86    #[inline]
87    pub fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> core::fmt::Result {
88        core::fmt::Write::write_fmt(self, args)
89    }
90
91    #[inline]
92    pub fn write_str(&mut self, s: &str) -> core::fmt::Result {
93        __println(self.0, s)
94    }
95
96    #[inline]
97    pub fn write_nl(&mut self) -> core::fmt::Result {
98        __println(self.0, "\n")
99    }
100}
101
102#[doc(hidden)]
103#[inline]
104pub fn __println(handle: i32, msg: &str) -> core::fmt::Result {
105    let msg = msg.as_bytes();
106
107    let mut written = 0;
108    while written < msg.len() {
109        match unsafe { write(handle, &msg[written..]) } {
110            // Ignore errors
111            None | Some(0) => break,
112            Some(res) => written += res,
113        }
114    }
115
116    Ok(())
117}
118
119unsafe fn write(handle: i32, bytes: &[u8]) -> Option<usize> {
120    usize::try_from(unsafe {
121        pros_sys::write(
122            handle,
123            bytes.as_ptr().cast::<core::ffi::c_void>(),
124            bytes.len(),
125        )
126    })
127    .ok()
128}
129
130/// Macro for printing to the standard output, with a newline.
131///
132/// Does not panic on failure to write - instead silently ignores errors.
133///
134/// See [`println!`](https://doc.rust-lang.org/std/macro.println.html) for
135/// full documentation.
136#[macro_export]
137macro_rules! println {
138    () => { $crate::println!("") };
139    ($($arg:tt)*) => {
140        {
141            #[allow(unused_must_use)]
142            {
143                let mut stm = $crate::io::__SerialWriter::new(false);
144                stm.write_fmt(format_args!($($arg)*));
145                stm.write_nl();
146            }
147        }
148    };
149}
150
151/// Macro for printing to the standard output.
152///
153/// Does not panic on failure to write - instead silently ignores errors.
154///
155/// See [`print!`](https://doc.rust-lang.org/std/macro.print.html) for
156/// full documentation.
157#[macro_export]
158macro_rules! print {
159    ($($arg:tt)*) => {
160        {
161            #[allow(unused_must_use)]
162            {
163                let mut stm = $crate::io::__SerialWriter::new(false);
164                stm.write_fmt(format_args!($($arg)*));
165            }
166        }
167    };
168}
169
170/// Macro for printing to the standard error, with a newline.
171///
172/// Does not panic on failure to write - instead silently ignores errors.
173///
174/// See [`eprintln!`](https://doc.rust-lang.org/std/macro.eprintln.html) for
175/// full documentation.
176#[macro_export]
177macro_rules! eprintln {
178    () => { $crate::eprintln!("") };
179    ($($arg:tt)*) => {
180        {
181            #[allow(unused_must_use)]
182            {
183                let mut stm = $crate::io::__SerialWriter::new(true);
184                stm.write_fmt(format_args!($($arg)*));
185                stm.write_nl();
186            }
187        }
188    };
189}
190
191/// Macro for printing to the standard error.
192///
193/// Does not panic on failure to write - instead silently ignores errors.
194///
195/// See [`eprint!`](https://doc.rust-lang.org/std/macro.eprint.html) for
196/// full documentation.
197#[macro_export]
198macro_rules! eprint {
199    ($($arg:tt)*) => {
200        {
201            #[allow(unused_must_use)]
202            {
203                let mut stm = $crate::io::__SerialWriter::new(true);
204                stm.write_fmt(format_args!($($arg)*));
205            }
206        }
207    };
208}
209
210/// Prints and returns the value of a given expression for quick and dirty
211/// debugging.
212///
213/// An example:
214///
215/// ```rust
216/// let a = 2;
217/// let b = dbg!(a * 2) + 1;
218/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
219/// assert_eq!(b, 5);
220/// ```
221///
222/// See [dbg!](https://doc.rust-lang.org/std/macro.dbg.html) for full documentation.
223#[macro_export]
224macro_rules! dbg {
225    () => {
226        $crate::eprintln!("[{}:{}]", $file!(), $line!())
227    };
228    ($val:expr $(,)?) => {
229        match $val {
230            tmp => {
231                $crate::eprintln!("[{}:{}] {} = {:#?}", file!(), line!(), stringify!($val), &tmp);
232                tmp
233            }
234        }
235    };
236    ($($val:expr),+ $(,)?) => {
237        ($($crate::dbg!($val)),+,)
238    };
239}