#![allow(clippy::needless_doctest_main, clippy::print_literal)]
#[cfg(feature = "derive")]
pub use proconio_derive::*;
pub mod marker;
pub mod source;
use crate::source::{line::LineSource, once::OnceSource};
use std::sync::OnceLock;
use std::{
io::{self, BufRead},
sync::Mutex,
};
use std::{
io::{BufReader, Stdin},
sync::MutexGuard,
};
#[doc(hidden)]
pub use crate::source::Readable as __Readable;
pub enum StdinSource<R: BufRead> {
Line(LineSource<R>), Once(OnceSource<R>), }
impl<R: BufRead> source::Source<R> for StdinSource<R> {
fn next_token(&mut self) -> Option<&str> {
match self {
StdinSource::Line(source) => source.next_token(),
StdinSource::Once(source) => source.next_token(),
}
}
fn is_empty(&mut self) -> bool {
match self {
StdinSource::Line(source) => source.is_empty(),
StdinSource::Once(source) => source.is_empty(),
}
}
}
#[doc(hidden)]
pub static STDIN_SOURCE: OnceLock<Mutex<StdinSource<BufReader<Stdin>>>> = OnceLock::new();
#[macro_export]
macro_rules! input {
(@from [$source:expr] @rest) => {};
(@from [$source:expr] @rest mut $($rest:tt)*) => {
$crate::input! {
@from [$source]
@mut [mut]
@rest $($rest)*
}
};
(@from [$source:expr] @rest $($rest:tt)*) => {
$crate::input! {
@from [$source]
@mut []
@rest $($rest)*
}
};
(@from [$source:expr] @mut [$($mut:tt)?] @rest $var:tt: $($rest:tt)*) => {
$crate::input! {
@from [$source]
@mut [$($mut)*]
@var $var
@kind []
@rest $($rest)*
}
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest with $($rest:tt)*) => {
$crate::input! {
@from [$source]
@mut [$($mut)*]
@var $var
@dyn_kind []
@rest $($rest)*
}
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [$($kind:tt)*] @rest) => {
let $($mut)* $var = $crate::read_value!(@source [$source] @kind [$($kind)*]);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [$($kind:tt)*] @rest, $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$($kind)*] @rest);
$crate::input!(@from [$source] @rest $($rest)*);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest [$($tt:tt)*] $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [[$($tt)*]] @rest $($rest)*);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest ($($tt:tt)*) $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [($($tt)*)] @rest $($rest)*);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest $ty:ty, $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$ty] @rest, $($rest)*);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest $ty:ty) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$ty] @rest);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest) => {
let $($mut)* $var = $crate::read_value!(@source [$source] @dyn_kind [$($dyn_kind)*]);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest, $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)*] @rest);
$crate::input!(@from [$source] @rest $($rest)*);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest $dyn_readable:expr) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)* $dyn_readable] @rest);
};
(@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest $dyn_readable:expr, $($rest:tt)*) => {
$crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)* $dyn_readable] @rest , $($rest)*);
};
(@from $($tt:tt)*) => {
compile_error!(concat!(
"Reached unreachable statement while parsing macro input. ",
"This is a bug in `proconio`. ",
"Please report this issue from ",
"<https://github.com/statiolake/proconio-rs/issues>."
));
};
(from $source:expr, $($rest:tt)*) => {
#[allow(unused_variables, unused_mut)]
let mut s = $source;
$crate::input! {
@from [&mut s]
@rest $($rest)*
}
};
($($rest:tt)*) => {
let mut locked_stdin = $crate::__acquire_global_stdin_lock_line();
$crate::input! {
@from [&mut *locked_stdin]
@rest $($rest)*
}
drop(locked_stdin); };
}
#[deprecated(
since = "0.6.0",
note = "`input!` now always reads the input line by line and works for interactive problems; use `input!` instead"
)]
#[macro_export]
macro_rules! input_interactive {
($($rest:tt)*) => {
$crate::input! {
$($rest)*
}
};
}
#[macro_export]
macro_rules! input_once {
(from $($rest:tt)*) => {
compile_error!(concat!(
"`input_once!` does not support the `from source` syntax. ",
"Use `input!` with your own source instead."
));
};
($($rest:tt)*) => {
let mut locked_stdin = $crate::__acquire_global_stdin_lock_once();
$crate::input! {
@from [&mut *locked_stdin]
@rest $($rest)*
}
drop(locked_stdin); };
}
#[macro_export]
macro_rules! read_value {
(@source [$source:expr] @kind [[$($kind:tt)*]]) => {
$crate::read_value!(@array @source [$source] @kind [] @rest $($kind)*)
};
(@array @source [$source:expr] @kind [$($kind:tt)*] @rest) => {{
let len = <usize as $crate::__Readable>::read($source);
$crate::read_value!(@source [$source] @kind [[$($kind)*; len]])
}};
(@array @source [$source:expr] @kind [$($kind:tt)*] @rest ; $($rest:tt)*) => {
$crate::read_value!(@array @source [$source] @kind [$($kind)*] @len [$($rest)*])
};
(@array @source [$source:expr] @kind [$($kind:tt)*] @rest $tt:tt $($rest:tt)*) => {
$crate::read_value!(@array @source [$source] @kind [$($kind)* $tt] @rest $($rest)*)
};
(@array @source [$source:expr] @kind [$($kind:tt)*] @len [$($len:tt)*]) => {{
let len = $($len)*;
(0..len)
.map(|_| $crate::read_value!(@source [$source] @kind [$($kind)*]))
.collect::<Vec<_>>()
}};
(@source [$source:expr] @kind [($($kinds:tt)*)]) => {
$crate::read_value!(@tuple @source [$source] @kinds [] @current [] @rest $($kinds)*)
};
(@tuple @source [$source:expr] @kinds [$([$($kind:tt)*])*] @current [] @rest) => {
(
$($crate::read_value!(@source [$source] @kind [$($kind)*]),)*
)
};
(@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest) => {
$crate::read_value!(@tuple @source [$source] @kinds [$($kinds)* [$($curr)*]] @current [] @rest)
};
(@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest, $($rest:tt)*) => {
$crate::read_value!(@tuple @source [$source] @kinds [$($kinds)* [$($curr)*]] @current [] @rest $($rest)*)
};
(@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest $tt:tt $($rest:tt)*) => {
$crate::read_value!(@tuple @source [$source] @kinds [$($kinds)*] @current [$($curr)* $tt] @rest $($rest)*)
};
(@source [$source:expr] @kind [$kind:ty]) => {
<$kind as $crate::__Readable>::read($source)
};
(@source [$source:expr] @dyn_kind [$dyn_kind:expr]) => {
$crate::source::RuntimeReadable::read($dyn_kind, $source)
};
(@source [$source:expr] @kind []) => {
compile_error!(concat!(
"Reached unreachable statement while parsing macro input. ",
"This is a bug in `proconio`. ",
"Please report this issue from ",
"<https://github.com/statiolake/proconio-rs/issues>."
));
};
(from $source:expr, with $($rest:tt)*) => {{
#[allow(unused_variables, unused_mut)]
let mut s = $source;
$crate::read_value!(@source [&mut s] @dyn_kind [$($rest)*])
}};
(from $source:expr, $($rest:tt)*) => {{
#[allow(unused_variables, unused_mut)]
let mut s = $source;
$crate::read_value!(@source [&mut s] @kind [$($rest)*])
}};
($($rest:tt)*) => {{
let mut locked_stdin = $crate::__acquire_global_stdin_lock_line();
let __res = $crate::read_value!(from &mut *locked_stdin, $($rest)*);
drop(locked_stdin); __res
}};
}
#[deprecated(
since = "0.6.0",
note = "`read_value!` now always reads the input line by line and works for interactive problems; use `read_value!` instead"
)]
#[macro_export]
macro_rules! read_value_interactive {
($($rest:tt)*) => {
$crate::read_value!($($rest)*)
};
}
#[macro_export]
macro_rules! read_value_once {
(from $($rest:tt)*) => {
compile_error!(concat!(
"`read_value_once!` does not support the `from source` syntax. ",
"Use `read_value!` with your own source instead."
));
};
($($rest:tt)*) => {{
let mut locked_stdin = $crate::__acquire_global_stdin_lock_once();
let __res = $crate::read_value!(from &mut *locked_stdin, $($rest)*);
drop(locked_stdin); __res
}};
}
#[doc(hidden)]
pub fn __acquire_global_stdin_lock_line() -> MutexGuard<'static, StdinSource<BufReader<Stdin>>> {
let locked_stdin = lock_global_stdin_source(|| {
StdinSource::Line(LineSource::new(BufReader::new(io::stdin())))
});
if let StdinSource::Once(_) = &*locked_stdin {
panic!(concat!(
"cannot use `input!` / `read_value!` (or their deprecated `_interactive` aliases) ",
"or `is_stdin_empty()` after `input_once!` / `read_value_once!`: the stdin source ",
"is already initialized to read the entire input at once. ",
"Please use only one family of the macros in a program."
));
}
locked_stdin
}
#[doc(hidden)]
pub fn __acquire_global_stdin_lock_once() -> MutexGuard<'static, StdinSource<BufReader<Stdin>>> {
let locked_stdin = lock_global_stdin_source(|| {
StdinSource::Once(OnceSource::new(BufReader::new(io::stdin())))
});
if let StdinSource::Line(_) = &*locked_stdin {
panic!(concat!(
"cannot use `input_once!` / `read_value_once!` after `input!` / `read_value!` ",
"(or their deprecated `_interactive` aliases) or `is_stdin_empty()`: the stdin ",
"source is already initialized to read the input line by line. ",
"Please use only one family of the macros in a program."
));
}
locked_stdin
}
fn lock_global_stdin_source(
init: impl FnOnce() -> StdinSource<BufReader<Stdin>>,
) -> MutexGuard<'static, StdinSource<BufReader<Stdin>>> {
STDIN_SOURCE
.get_or_init(|| Mutex::new(init()))
.lock()
.expect(concat!(
"failed to lock the stdin; please re-run this program. ",
"If this issue repeatedly occur, this is a bug in `proconio`. ",
"Please report this issue from ",
"<https://github.com/statiolake/proconio-rs/issues>."
))
}
pub fn is_stdin_empty() -> bool {
use source::Source;
let mut lock = lock_global_stdin_source(|| {
StdinSource::Line(LineSource::new(BufReader::new(io::stdin())))
});
lock.is_empty()
}
#[cfg(test)]
mod tests {
use std::marker::PhantomData;
use crate::source::auto::AutoSource;
#[test]
fn input_empty() {
let source = AutoSource::from("");
input! {
from source,
}
}
#[test]
fn input_number() {
let source = AutoSource::from(" 32 54 -23\r\r\n\nfalse");
input! {
from source,
n: u8,
m: u32,
l: i32,
}
assert_eq!(n, 32);
assert_eq!(m, 54);
assert_eq!(l, -23);
}
#[test]
fn read_value_number() {
let mut source = AutoSource::from(" 32 54 -23\r\r\n\nfalse");
assert_eq!(read_value!(from &mut source, u8), 32);
assert_eq!(read_value!(from &mut source, u32), 54);
assert_eq!(read_value!(from &mut source, i32), -23);
}
#[test]
fn input_str() {
use crate::marker::{Bytes, Chars};
let source = AutoSource::from(" string chars\nbytes");
input! {
from source,
string: String,
chars: Chars,
bytes: Bytes,
}
assert_eq!(string, "string");
assert_eq!(chars, ['c', 'h', 'a', 'r', 's']);
assert_eq!(bytes, b"bytes");
}
#[test]
fn read_value_str() {
use crate::marker::{Bytes, Chars};
let mut source = AutoSource::from(" string chars\nbytes");
assert_eq!(read_value!(from &mut source, String), "string");
assert_eq!(
read_value!(from &mut source, Chars),
['c', 'h', 'a', 'r', 's']
);
assert_eq!(read_value!(from &mut source, Bytes), b"bytes");
}
#[test]
fn input_array() {
let source = AutoSource::from("5 3 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5");
input! {
from source,
n: usize,
m: usize,
a: [i32; n],
b: [[i32; n]; m] }
assert_eq!(a, [1, 2, 3, 4, 5]);
assert_eq!(b, [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);
}
#[test]
fn read_value_array() {
let mut source = AutoSource::from("5 3 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5");
let n = read_value!(from &mut source, usize);
let m = read_value!(from &mut source, usize);
let a = read_value!(from &mut source, [i32; n]);
let b = read_value!(from &mut source, [[i32; n]; m]);
assert_eq!(a, [1, 2, 3, 4, 5]);
assert_eq!(b, [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);
}
#[test]
fn input_vla() {
let source = AutoSource::from("5 3 1 2 3 2 1 2 4 1 2 3 4 0 6 1 2 3 4 5 6");
input! {
from source,
n: usize,
a: [[i32]; n],
}
assert_eq!(
a,
vec![
vec![1, 2, 3],
vec![1, 2],
vec![1, 2, 3, 4],
vec![],
vec![1, 2, 3, 4, 5, 6],
]
);
}
#[test]
fn read_value_vla() {
let mut source = AutoSource::from("5 3 1 2 3 2 1 2 4 1 2 3 4 0 6 1 2 3 4 5 6");
let n = read_value!(from &mut source, usize);
let a = read_value!(from &mut source, [[i32]; n]);
assert_eq!(
a,
vec![
vec![1, 2, 3],
vec![1, 2],
vec![1, 2, 3, 4],
vec![],
vec![1, 2, 3, 4, 5, 6],
]
);
}
#[test]
fn input_tuple() {
let mut source = AutoSource::from("4 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5");
let n = read_value!(from &mut source, usize);
let t = read_value!(from &mut source, [(i32, i32, i32, i32, i32); n]);
assert_eq!(
t,
[
(1, 2, 3, 4, 5),
(1, 2, 3, 4, 5),
(1, 2, 3, 4, 5),
(1, 2, 3, 4, 5)
]
);
}
#[test]
fn input_multiple_times() {
let mut source = AutoSource::from("4 1 2 3 4\n1 2\r\n\r\r\n3 4");
input! {
from &mut source,
n: usize,
}
for i in 0..n {
input! {
from &mut source,
j: i32, k: i32,
}
assert_eq!(j, if i % 2 == 0 { 1 } else { 3 });
assert_eq!(k, if i % 2 == 0 { 2 } else { 4 });
}
}
#[test]
fn input_iusize1() {
use crate::marker::Usize1;
let mut source = AutoSource::from("4 1 2 3 4 5 6 7 8");
input! {
from &mut source,
n: usize,
}
for i in 0..n {
input! {
from &mut source,
from: Usize1, to: Usize1
}
assert_eq!(from, i * 2);
assert_eq!(to, i * 2 + 1);
}
}
#[test]
#[should_panic]
fn input_zero_as_usize1() {
use crate::marker::Usize1;
let mut source = AutoSource::from("0");
input! {
from &mut source,
_v: Usize1,
}
}
#[test]
#[should_panic]
fn input_min_as_isize1() {
use crate::marker::Isize1;
let min_string = isize::MIN.to_string();
let mut source = AutoSource::from(&*min_string);
input! {
from &mut source,
_v: Isize1,
}
}
#[test]
fn input_mut() {
let mut source = AutoSource::from("8 1 2 3 4 5 6 7 8");
input! {
from &mut source,
mut n: usize,
}
let mut sum = 0;
while n > 0 {
input!(from &mut source, x: u32);
sum += x;
n -= 1;
}
assert_eq!(sum, 36);
}
#[test]
fn input_with_complex_type() {
let mut source = AutoSource::from("Hello\n2\n3 1 2 3\n4 5 ab\n4");
input! {
from &mut source,
hello: crate::marker::Bytes,
from: crate::marker::Usize1,
vla: [crate::marker::Isize1],
tuple: (crate::marker::Usize1, crate::marker::Isize1, crate::marker::Chars),
unit: (crate::marker::Usize1),
}
assert_eq!(hello, b"Hello");
assert_eq!(from, 1);
assert_eq!(vla, [0, 1, 2]);
assert_eq!(tuple, (3, 4, vec!['a', 'b']));
assert_eq!(unit, (3,));
}
#[test]
fn input_single_tt_pattern() {
let mut source = AutoSource::from("3 42 0\n1 2 3\n");
input! {
from &mut source,
(n, mut k): (usize, usize),
_: usize,
xs: [u32; n],
}
k += 1;
assert_eq!(n, 3);
assert_eq!(k, 43);
assert_eq!(xs, [1, 2, 3]);
}
#[test]
fn input_generic() {
enum Array<T, const N: usize> {
_Phantom(
std::convert::Infallible,
std::marker::PhantomData<fn() -> T>,
),
}
impl<T: crate::source::Readable, const N: usize> crate::source::Readable for Array<T, N> {
type Output = [T::Output; N];
fn read<R: std::io::BufRead, S: crate::source::Source<R>>(
source: &mut S,
) -> Self::Output {
std::array::from_fn(|_| T::read(source))
}
}
let source = AutoSource::from("1 2 3 4 5 6 7 8");
input! {
from source,
a: Array<i32, 5>,
b: Array<i32, 3>,
}
assert_eq!(a, [1, 2, 3, 4, 5]);
assert_eq!(b, [6, 7, 8]);
}
#[test]
fn read_value_generic() {
enum Array<T, const N: usize> {
_Phantom(
std::convert::Infallible,
std::marker::PhantomData<fn() -> T>,
),
}
impl<T: crate::source::Readable, const N: usize> crate::source::Readable for Array<T, N> {
type Output = [T::Output; N];
fn read<R: std::io::BufRead, S: crate::source::Source<R>>(
source: &mut S,
) -> Self::Output {
std::array::from_fn(|_| T::read(source))
}
}
let mut source = AutoSource::from("1 2 3 4 5 6 7 8");
let a = read_value!(from &mut source, Array<i32, 5>);
let b = read_value!(from &mut source, Array<i32, 3>);
assert_eq!(a, [1, 2, 3, 4, 5]);
assert_eq!(b, [6, 7, 8]);
}
#[test]
fn input_runtime_readable() {
struct VecReadable<T> {
n: usize,
_marker: PhantomData<T>,
}
impl<T> VecReadable<T> {
pub fn new(n: usize) -> Self {
VecReadable {
n,
_marker: PhantomData,
}
}
}
impl<T: crate::source::Readable> crate::source::RuntimeReadable for VecReadable<T> {
type Output = Vec<T::Output>;
fn read<R: std::io::BufRead, S: crate::source::Source<R>>(
self,
source: &mut S,
) -> Self::Output {
let mut res = vec![];
for _ in 0..self.n {
input! {
from &mut *source,
v: T,
}
res.push(v);
}
res
}
}
let mut source = AutoSource::from("4 1 2 3 4");
input! {
from &mut source,
n: usize,
v: with VecReadable::<crate::marker::Usize1>::new(n),
}
assert_eq!(v, [0, 1, 2, 3]);
}
#[test]
fn read_value_runtime_readable() {
struct VecReadable<T> {
n: usize,
_marker: PhantomData<T>,
}
impl<T> VecReadable<T> {
pub fn new(n: usize) -> Self {
VecReadable {
n,
_marker: PhantomData,
}
}
}
impl<T: crate::source::Readable> crate::source::RuntimeReadable for VecReadable<T> {
type Output = Vec<T::Output>;
fn read<R: std::io::BufRead, S: crate::source::Source<R>>(
self,
source: &mut S,
) -> Self::Output {
let mut res = vec![];
for _ in 0..self.n {
input! {
from &mut *source,
v: T,
}
res.push(v);
}
res
}
}
let mut source = AutoSource::from("4 1 2 3 4");
let n = read_value!(from &mut source, usize);
let v = read_value!(from &mut source, with VecReadable::<crate::marker::Usize1>::new(n));
assert_eq!(v, [0, 1, 2, 3]);
}
#[test]
#[should_panic]
fn input_err_different_type() {
let mut source = AutoSource::from("3.2\n");
input! {
from &mut source,
_n: i32,
}
}
#[test]
#[should_panic]
fn input_err_different_format() {
let mut source = AutoSource::from("");
input! {
from &mut source,
_n: i32,
}
}
}