use core::{
cell::RefCell,
fmt,
panic::{RefUnwindSafe, UnwindSafe},
};
use alloc::{string::String, vec::Vec};
use crate::{
io::{self, BorrowedCursor, BufRead, BufReader, LineWriter, Lines, Read, Write},
os,
sync::{
nonpoison::{OnceLock, ReentrantLock, ReentrantLockGuard},
poison::{Mutex, MutexGuard},
},
sys::SceError,
};
pub struct StdinRaw(os::stdio::Stdin);
pub struct StdoutRaw(os::stdio::Stdout);
pub struct StderrRaw(os::stdio::Stderr);
pub const fn stdin_raw() -> StdinRaw {
StdinRaw(os::stdio::Stdin::new())
}
pub const fn stdout_raw() -> StdoutRaw {
StdoutRaw(os::stdio::Stdout::new())
}
pub const fn stderr_raw() -> StderrRaw {
StderrRaw(os::stdio::Stderr::new())
}
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
handle_ebadf(self.0.read(buf), || Ok(0))
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
handle_ebadf(self.0.read_buf(buf), || Ok(()))
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
handle_ebadf(self.0.read_vectored(bufs), || Ok(0))
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.is_empty() {
return Ok(());
}
handle_ebadf(self.0.read_exact(buf), || {
Err(io_core::io_const_error!(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer"
))
})
}
fn read_buf_exact(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
if buf.capacity() == 0 {
return Ok(());
}
handle_ebadf(self.0.read_buf_exact(buf), || {
Err(io_core::io_const_error!(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer"
))
})
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
handle_ebadf(self.0.read_to_end(buf), || Ok(0))
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
handle_ebadf(self.0.read_to_string(buf), || Ok(0))
}
}
impl Write for StdoutRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
handle_ebadf(self.0.write(buf), || Ok(buf.len()))
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
let total = || Ok(bufs.iter().map(|b| b.len()).sum());
handle_ebadf(self.0.write_vectored(bufs), total)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
handle_ebadf(self.0.flush(), || Ok(()))
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
handle_ebadf(self.0.write_all(buf), || Ok(()))
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
}
}
impl Write for StderrRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
handle_ebadf(self.0.write(buf), || Ok(buf.len()))
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
let total = || Ok(bufs.iter().map(|b| b.len()).sum());
handle_ebadf(self.0.write_vectored(bufs), total)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
handle_ebadf(self.0.flush(), || Ok(()))
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
handle_ebadf(self.0.write_all(buf), || Ok(()))
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
handle_ebadf(self.0.write_all_vectored(bufs), || Ok(()))
}
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
handle_ebadf(self.0.write_fmt(fmt), || Ok(()))
}
}
fn handle_ebadf<T>(r: io::Result<T>, default: impl FnOnce() -> io::Result<T>) -> io::Result<T> {
match r {
Err(ref e) if is_ebadf(e) => default(),
r => r,
}
}
pub fn is_ebadf(err: &io::Error) -> bool {
let raw = err.raw_os_error();
raw == Some(SceError::BAD_FILE.to_inner() as i32)
|| raw == Some(SceError::KERNEL_BADF.to_inner() as i32)
}
pub struct Stdin {
inner: &'static Mutex<BufReader<StdinRaw>>,
}
#[must_use = "if unused stdin will immediately unlock"]
pub struct StdinLock<'a> {
inner: MutexGuard<'a, BufReader<StdinRaw>>,
}
#[must_use]
pub fn stdin() -> Stdin {
static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = OnceLock::new();
Stdin {
inner: INSTANCE.get_or_init(|| {
Mutex::new(BufReader::with_capacity(os::stdio::STDIN_BUF_SIZE, stdin_raw()))
}),
}
}
impl Stdin {
pub fn lock(&self) -> StdinLock<'static> {
StdinLock {
inner: self.inner.lock_unchecked(),
}
}
pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
self.lock().read_line(buf)
}
#[must_use = "`self` will be dropped if the result is not used"]
pub fn lines(self) -> Lines<StdinLock<'static>> {
self.lock().lines()
}
}
impl fmt::Debug for Stdin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Stdin").finish_non_exhaustive()
}
}
impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
self.lock().read_buf(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.lock().read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.lock().is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.lock().read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.lock().read_exact(buf)
}
}
impl Read for &Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
self.lock().read_buf(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.lock().read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.lock().is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.lock().read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.lock().read_exact(buf)
}
}
impl StdinLock<'_> {
#[allow(unused)]
pub(crate) fn as_mut_buf(&mut self) -> &mut BufReader<impl Read> {
&mut self.inner
}
}
impl Read for StdinLock<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
self.inner.read_buf(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.inner.read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.inner.read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.inner.read_exact(buf)
}
}
impl BufRead for StdinLock<'_> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, n: usize) {
self.inner.consume(n)
}
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
self.inner.read_until(byte, buf)
}
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
self.inner.read_line(buf)
}
}
impl fmt::Debug for StdinLock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StdinLock").finish_non_exhaustive()
}
}
pub struct Stdout {
inner: &'static ReentrantLock<RefCell<LineWriter<StdoutRaw>>>,
}
#[must_use = "if unused stdout will immediately unlock"]
pub struct StdoutLock<'a> {
inner: ReentrantLockGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
}
static STDOUT: OnceLock<ReentrantLock<RefCell<LineWriter<StdoutRaw>>>> = OnceLock::new();
#[must_use]
pub fn stdout() -> Stdout {
Stdout {
inner: STDOUT
.get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(stdout_raw())))),
}
}
#[allow(dead_code)] pub fn cleanup() {
let mut initialized = false;
let stdout = STDOUT.get_or_init(|| {
initialized = true;
ReentrantLock::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
});
if !initialized {
if let Some(lock) = stdout.try_lock() {
*lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
}
}
}
impl Stdout {
pub fn lock(&self) -> StdoutLock<'static> {
StdoutLock {
inner: self.inner.lock(),
}
}
}
impl UnwindSafe for Stdout {}
impl RefUnwindSafe for Stdout {}
impl fmt::Debug for Stdout {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Stdout").finish_non_exhaustive()
}
}
impl Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(&*self).write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
(&*self).write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
io::Write::is_write_vectored(&self)
}
fn flush(&mut self) -> io::Result<()> {
(&*self).flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(&*self).write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
(&*self).write_all_vectored(bufs)
}
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
(&*self).write_fmt(args)
}
}
impl Write for &Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.lock().write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.lock().write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.lock().is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
self.lock().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
self.lock().write_all_vectored(bufs)
}
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
impl UnwindSafe for StdoutLock<'_> {}
impl RefUnwindSafe for StdoutLock<'_> {}
impl Write for StdoutLock<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.borrow_mut().write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.inner.borrow_mut().write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.inner.borrow_mut().is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.inner.borrow_mut().write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
self.inner.borrow_mut().write_all_vectored(bufs)
}
}
impl fmt::Debug for StdoutLock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StdoutLock").finish_non_exhaustive()
}
}
pub struct Stderr {
inner: &'static ReentrantLock<RefCell<StderrRaw>>,
}
#[must_use = "if unused stderr will immediately unlock"]
pub struct StderrLock<'a> {
inner: ReentrantLockGuard<'a, RefCell<StderrRaw>>,
}
#[must_use]
pub fn stderr() -> Stderr {
static INSTANCE: ReentrantLock<RefCell<StderrRaw>> =
ReentrantLock::new(RefCell::new(stderr_raw()));
Stderr { inner: &INSTANCE }
}
impl Stderr {
pub fn lock(&self) -> StderrLock<'static> {
StderrLock {
inner: self.inner.lock(),
}
}
}
impl UnwindSafe for Stderr {}
impl RefUnwindSafe for Stderr {}
impl fmt::Debug for Stderr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Stderr").finish_non_exhaustive()
}
}
impl Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(&*self).write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
(&*self).write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
io::Write::is_write_vectored(&self)
}
fn flush(&mut self) -> io::Result<()> {
(&*self).flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(&*self).write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
(&*self).write_all_vectored(bufs)
}
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
(&*self).write_fmt(args)
}
}
impl Write for &Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.lock().write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.lock().write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.lock().is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
self.lock().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
self.lock().write_all_vectored(bufs)
}
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
impl UnwindSafe for StderrLock<'_> {}
impl RefUnwindSafe for StderrLock<'_> {}
impl Write for StderrLock<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.borrow_mut().write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.inner.borrow_mut().write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.inner.borrow_mut().is_write_vectored()
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.inner.borrow_mut().write_all(buf)
}
fn write_all_vectored(&mut self, bufs: &mut [io::IoSlice<'_>]) -> io::Result<()> {
self.inner.borrow_mut().write_all_vectored(bufs)
}
}
impl fmt::Debug for StderrLock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StderrLock").finish_non_exhaustive()
}
}