use crate::errors::{error, nil, New};
use crate::types::{byte, string};
use std::io::BufRead;
pub struct Scanner<R: BufRead> {
reader: R,
buf: String,
last_err: error,
done: bool,
}
#[allow(non_snake_case)]
pub fn NewScanner<R: BufRead>(r: R) -> Scanner<R> {
Scanner {
reader: r,
buf: String::new(),
last_err: nil,
done: false,
}
}
impl<R: BufRead> Scanner<R> {
pub fn Scan(&mut self) -> bool {
if self.done {
return false;
}
self.buf.clear();
match self.reader.read_line(&mut self.buf) {
Ok(0) => {
self.done = true;
false
}
Ok(_) => {
if self.buf.ends_with('\n') {
self.buf.pop();
if self.buf.ends_with('\r') {
self.buf.pop();
}
}
true
}
Err(e) => {
self.last_err = New(&format!("bufio.Scanner: {}", e));
self.done = true;
false
}
}
}
pub fn Text(&self) -> &str {
&self.buf
}
pub fn Bytes(&self) -> &[byte] {
self.buf.as_bytes()
}
pub fn Err(&self) -> &error {
&self.last_err
}
}
#[allow(non_snake_case)]
pub fn ReadLines<R: BufRead>(r: R) -> (crate::types::slice<string>, error) {
let mut sc = NewScanner(r);
let mut lines = crate::types::slice::<string>::new();
while sc.Scan() {
lines.push(sc.Text().to_string());
}
let err = sc.Err().clone();
(lines, err)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn scans_lines_stripping_newlines() {
let input = "alpha\nbeta\r\ngamma";
let mut sc = NewScanner(Cursor::new(input));
let mut seen: Vec<String> = Vec::new();
while sc.Scan() {
seen.push(sc.Text().to_string());
}
assert_eq!(seen, vec!["alpha", "beta", "gamma"]);
assert!(sc.Err() == &nil);
}
#[test]
fn empty_reader_scan_returns_false() {
let mut sc = NewScanner(Cursor::new(""));
assert!(!sc.Scan());
assert!(sc.Err() == &nil);
}
#[test]
fn read_lines_convenience() {
let (lines, err) = ReadLines(Cursor::new("one\ntwo\nthree\n"));
assert!(err == nil);
assert_eq!(lines, vec!["one", "two", "three"]);
}
}