1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
// Remove when bumping minimum Rust version to 1.27 #![allow(bare_trait_objects)] //! Crate for reading whitespace-separated values. //! //! The crate defines a trait [`FromStream`](stream::FromStream), which //! describes types that can be parsed from whitespace-separated words, //! which includes eg. integers, tuples, vectors and various [adapters]. //! //! The definition of whitespace used in this crate is described in //! [`SplitAsciiWhitespace`](stream::SplitAsciiWhitespace). //! //! # Examples //! //! Basics //! //! ``` //! # use whiteread::parse_string; //! let (s, i): (String, i32) = parse_string(" answer 42 ").unwrap(); //! # assert!(s == "answer" && i == 42); //! ``` //! //! Easy reading from stdin. //! //! ```no_run //! # use whiteread::parse_line; //! let x: i32 = parse_line().unwrap(); //! ``` //! //! Efficient reading from stdin (newline-agnostic) with [`Reader`](reader::Reader). //! //! ```no_run //! # use whiteread::Reader; //! # foo().unwrap(); //! # fn foo() -> whiteread::reader::Result<()> { //! let mut i = Reader::from_stdin_naive(); //! while let Some(f) = i.parse::<Option<f64>>()? { //! println!("{}", f); //! } //! # Ok(()) //! # } //! ``` use std::io; use std::path::Path; pub mod stream; pub use self::stream::FromStream; pub mod adapters; pub mod reader; pub use self::reader::Reader; // Helpers ----------------------------------------------------------------------------------------- /// Parse [`FromStream`] value from one line of stdin. /// /// Leftovers are considered an error. /// /// # Examples /// ```no_run /// # use whiteread::parse_line; /// let x: i32 = parse_line().unwrap(); /// ``` /// /// # Drawbacks and alternatives /// /// This function locks a mutex and allocates a buffer, so /// don't use it when reading more than few lines – /// use [`Reader`](reader::Reader) or [`parse_stdin`] instead. /// /// Note that reported line number will be wrong if you're mixing this function with other ways to /// read stdin. pub fn parse_line<T: FromStream>() -> reader::Result<T> { use std::sync::atomic; #[allow(deprecated)] // suggested AtomicUsize::new() doesn't work on 1.20 static LINE_NUMBER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT; let row = 1 + LINE_NUMBER.fetch_add(1, atomic::Ordering::Relaxed); let mut line = String::new(); io::stdin().read_line(&mut line)?; Reader::single_line(row as u64, line).finish_line() } /// Parse [`FromStream`] value from string. /// /// Leftovers are considered an error. /// /// # Examples /// ``` /// # use whiteread::parse_string; /// let number: i32 = parse_string(" 123 ").unwrap(); /// assert!(number == 123); /// ``` pub fn parse_string<T: FromStream>(s: &str) -> stream::Result<T> { let mut stream = stream::SplitAsciiWhitespace::new(s); let value = FromStream::read(&mut stream)?; if let Ok(Some(_)) = stream::StrStream::next(&mut stream) { Err(stream::Error::Leftovers) } else { Ok(value) } } /// Parse the whole stdin as a [`FromStream`] value /// /// Use [`Reader`](reader::Reader) if you want more complex logic. /// /// # Examples /// ``` /// # use whiteread::parse_stdin; /// /// Read whitespace-separated numbers from stdin, newline agnostic. /// let numbers: Vec<i32> = parse_stdin().unwrap(); /// ``` pub fn parse_stdin<T: FromStream>() -> reader::Result<T> { let stdin = io::stdin(); // Explicit return is necessary here to shorten the lifetime of `stdin.lock()` return Reader::new(stdin.lock()).finish(); } /// Parses a whole file as a [`FromStream`] value /// /// Calling this function is equivalent to: /// /// ```no_run /// # use whiteread::{Reader, reader, FromStream}; /// # fn foo<T: FromStream>() -> reader::Result<T> { /// # let path = "foo"; /// # Ok( /// Reader::open(path)?.finish()? /// # ) /// # } /// ``` /// /// If you want to parse the file in multiple steps, /// use [`Reader::open`](crate::reader::Reader::open). /// /// # Examples /// /// Parse the whole file as an tuple. /// /// ```no_run /// # use whiteread::parse_file; /// let x: (i32, i32) = parse_file("coords.txt").unwrap(); /// ``` pub fn parse_file<T: FromStream, P: AsRef<Path>>(path: P) -> reader::Result<T> { Ok(Reader::open(path)?.finish()?) }