1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use std::io::{self, BufRead, Read};
5
6pub mod prelude {
8 pub use crate::{
9 StdinSource, read_line_from, read_stdin_line, read_stdin_to_string, read_to_string_from,
10 };
11}
12
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
15pub struct StdinSource;
16
17impl StdinSource {
18 #[must_use]
20 pub const fn new() -> Self {
21 Self
22 }
23}
24
25pub fn read_stdin_to_string() -> io::Result<String> {
31 let stdin = io::stdin();
32 read_to_string_from(stdin.lock())
33}
34
35pub fn read_stdin_line() -> io::Result<String> {
41 let stdin = io::stdin();
42 read_line_from(stdin.lock())
43}
44
45pub fn read_to_string_from(mut reader: impl Read) -> io::Result<String> {
51 let mut input = String::new();
52 reader.read_to_string(&mut input)?;
53 Ok(input)
54}
55
56pub fn read_line_from(mut reader: impl BufRead) -> io::Result<String> {
62 let mut input = String::new();
63 reader.read_line(&mut input)?;
64 Ok(input)
65}
66
67#[cfg(test)]
68mod tests {
69 use std::io::Cursor;
70
71 use super::{StdinSource, read_line_from, read_to_string_from};
72
73 #[test]
74 fn marker_is_copyable() {
75 let source = StdinSource::new();
76 let copied = source;
77
78 assert_eq!(source, copied);
79 }
80
81 #[test]
82 fn reads_from_generic_readers() -> Result<(), std::io::Error> {
83 assert_eq!(read_to_string_from(Cursor::new("hello"))?, "hello");
84 assert_eq!(read_line_from(Cursor::new("first\nsecond"))?, "first\n");
85 Ok(())
86 }
87}