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
//! Crate for reading whitespace-separated values.
//!
//! The crate defines a trait [`White`](trait.White.html), which
//! describes types that can be parsed from whitespace-separated words,
//! which includes eg. integers, tuples and vectors.
//!
//! The definition of whitespace used in this crate is described in
//! [`SplitAsciiWhitespace`](stream/struct.SplitAsciiWhitespace.html).
//!
//! # 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`](struct.Reader.html).
//! Stops on error.
//!
//! ```no_run
//! # use whiteread::Reader;
//! let i = std::io::stdin();
//! let mut i = Reader::new(i.lock());
//! while let Ok(f) = i.parse::<f64>() {
//!     println!("{}", f);
//! }
//! ```
//!
//! If you want better error handling in while-let loops
//! (stop on end of input, but propagate all the other errors),
//! use [`none_on_too_short`](reader/trait.BorrowedResultExt.html#tymethod.none_on_too_short)

use std::path::Path;
use std::io;

pub mod stream;

pub mod white;
pub use self::white::{White, Skip, SkipAll, Lengthed, Zeroed};
pub use self::white::{TooShort, ParseError, Leftovers};

pub mod reader;
pub use self::reader::Reader;
pub use self::reader::OwnedError as ReaderError;
pub use self::reader::OwnedResult as ReaderResult;

/// Reexports of traits containing the extension methods.
///
/// The prelude is usually glob-imported:
///
/// ```
/// use whiteread::prelude::*;
/// ```
pub mod prelude {
    pub use super::reader::BorrowedResultExt;
    pub use super::reader::PrettyUnwrap;
}

// Helpers -----------------------------------------------------------------------------------------

/// Helper function for parsing `White` value from one line of stdin.
///
/// Leftovers are considered an error.
/// This function locks a mutex and allocates a buffer, so
/// don't use it when reading more than few lines –
/// use [`Reader`](struct.Reader.html) instead.
///
/// # Examples
/// ```no_run
/// # use whiteread::parse_line;
/// let x: i32 = parse_line().unwrap();
/// ```
pub fn parse_line<T: White>() -> white::Result<T> {
    let mut line = String::new();
    io::stdin().read_line(&mut line)?;
    parse_string(&line)
}

/// Helper function for parsing `White` 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: White>(s: &str) -> white::Result<T> {
    let mut stream = stream::SplitAsciiWhitespace::new(s);
    let value = White::read(&mut stream)?;

    if let Ok(Some(_)) = stream::StrStream::next(&mut stream) {
        Err(Leftovers)
    } else {
        Ok(value)
    }
}

/// Parses a whole file as a `White` value
///
/// Calling this function is equivalent to:
///
/// ```no_run
/// # use whiteread::{Reader, ReaderResult, White};
/// # fn foo<T: White>() -> ReaderResult<T> {
/// # let path = "foo";
/// # Ok(
/// Reader::open(path)?.finish()?
/// # )
/// # }
/// ```
///
/// If you want to parse the file in multiple steps,
/// use [`Reader::open`](struct.Reader.html#method.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: White, P: AsRef<Path>>(path: P) -> ReaderResult<T> {
    Ok( Reader::open(path)?.finish()? )
}