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}