Skip to content

Commit

Permalink
Replace BufRead with buf_redux::BufReader
Browse files Browse the repository at this point in the history
  • Loading branch information
hxtk committed Feb 4, 2018
1 parent c673bbb commit 36c64a3
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 52 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "file_scanner"
description = "Advanced text input handler patterned after java.util.Scanner"
version = "0.1.4"
version = "1.0.0"
authors = ["hxtk <peter@psanders.me>"]
license = "MIT"
repository = "https://github.com/hxtk/Rust-Scanner"
Expand All @@ -14,6 +14,7 @@ categories = ["Parsing"]
[dependencies]
regex = "0.2.5"
num = "0.1.41"
buf_redux = "0.6.1"

[badges]
travis-ci = { repository = "hxtk/Rust-Scanner", branch = "0.1.4" }
Expand Down
18 changes: 10 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
// Copyright (c) Peter Sanders. All rights reserved.
// Date: 2018-02-03
extern crate buf_redux;
extern crate num;
extern crate regex;

use std::io::Read;
use std::io::BufRead;
//use std::io::Read; // Pending issue #5
use std::marker::Sized;
use std::str;

use buf_redux::BufReader;
use regex::Regex; // For regex "delim"
use num::Integer;
use num::Float;

mod elastic_queue;
#[cfg(test)]
mod tests;

/// Rust implementation of java.util.Scanner
pub struct Scanner<'a> {
stream: &'a mut BufRead, // Underlying stream object we are handling.
pub struct Scanner<R: Read + Sized> {
stream: BufReader<R>, // Underlying stream object we are handling.
delim: Regex, // Delimiter used to specify word boundaries.
radix: u32, // Base in which we parse numeric types.

Expand All @@ -27,7 +29,7 @@ pub struct Scanner<'a> {

/// Implements the meta-methods of Scanner that affect how the data stream
/// is processed, e.g., delimiter, parsing radix, etc.
impl<'a> Scanner<'a> {
impl<R: Read + Sized> Scanner<R> {
/// Sets the delimiter to be some pre-compiled regex and return it
/// for behavioral consistency.
pub fn set_delim(&mut self, delim: Regex) -> &Regex {
Expand Down Expand Up @@ -77,9 +79,9 @@ impl<'a> Scanner<'a> {
}

/// Implements the methods of Scanner that affect the underlying data stream
impl<'a> Scanner<'a> {
impl<R: Read + Sized> Scanner<R> {
/// Creates a new instance of Scanner on some object implementing `BufRead`
pub fn new(stream: &'a mut BufRead) -> Scanner {
pub fn new(stream: BufReader<R>) -> Scanner<R> {
Scanner {
stream: stream,
// We can safely unwrap this regex because it is hard-coded.
Expand Down Expand Up @@ -272,7 +274,7 @@ impl<'a> Scanner<'a> {


/// Private helper functions for Scanner
impl<'a> Scanner<'a> {
impl<R: Read + Sized> Scanner<R> {
/// When we read `Scanner.next()`, we must first skip over any strings
/// in the delimiting language before we begin reading the target text.
fn consume_leading_delims(&mut self) {
Expand Down
84 changes: 41 additions & 43 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@
// Date: 2018-02-03
//
// Unit tests for Rust implementation of Scanner.
extern crate buf_redux;

use super::*;

use std::io::BufReader;
use buf_redux::BufReader;

#[test]
fn next_works_once_when_good_input() {
let mut string: &[u8] = b"hello";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next(), Some(String::from("hello")));
}

#[test]
fn next_breaks_at_delim() {
let mut string: &[u8] = b"hello, world";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello, world";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next(), Some(String::from("hello,")));
}

#[test]
fn next_skips_leading_delims() {
let mut string: &[u8] = b"hello, world";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello, world";
let mut test = Scanner::new(BufReader::new(string));
test.next();

assert_eq!(test.next(), Some(String::from("world")));
Expand All @@ -37,76 +39,76 @@ fn next_skips_leading_delims() {
/// delimiter.
#[test]
fn next_preserves_trailing_delim() {
let mut string: &[u8] = b"hello, world";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello, world";
let mut test = Scanner::new(BufReader::new(string));

test.next();
assert_eq!(test.next_line(), Some(String::from(" world")));
}

#[test]
fn next_handles_line_wrap() {
let mut string: &[u8] = b"hello\nworld";
let mut test = Scanner::new(&mut string);
let string: &[u8] = b"hello\nworld";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next(), Some(String::from("hello")));
}

#[test]
fn next_line_reads_whole_line() {
let mut string: &[u8] = b"hello, world\ngoodbye, world";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello, world\ngoodbye, world";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next_line(), Some(String::from("hello, world")));
}

#[test]
fn next_line_reads_last_line() {
let mut string: &[u8] = b"foo bar baz";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"foo bar baz";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next_line(), Some(String::from("foo bar baz")));
}

#[test]
fn next_works_after_next_line() {
let mut string: &[u8] = b"hello, world\ngoodbye, world";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"hello, world\ngoodbye, world";
let mut test = Scanner::new(BufReader::new(string));
test.next_line();

assert_eq!(test.next(), Some(String::from("goodbye,")));
}

#[test]
fn next_int_handles_commas() {
let mut string: &[u8] = b"2,147,483,647";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"2,147,483,647";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next_int::<i32>(), Some(2147483647));
}

#[test]
fn next_int_none_on_positive_overflow() {
let mut string: &[u8] = b"2147483648";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"2147483648";
let mut test = Scanner::new(BufReader::new(string));

let res = test.next_int::<i32>();
assert_eq!(res, None);
}

#[test]
fn next_i32_none_on_negative_overflow() {
let mut string: &[u8] = b"-2147483649";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"-2147483649";
let mut test = Scanner::new(BufReader::new(string));

let res = test.next_int::<i32>();
assert_eq!(res, None);
}

#[test]
fn arbitrary_delim() {
let mut string: &[u8] = b"foohello, worldfoo";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"foohello, worldfoo";
let mut test = Scanner::new(BufReader::new(string));
test.set_delim(Regex::new(r"foo").unwrap());

if let Some(res) = test.next() {
Expand All @@ -118,16 +120,16 @@ fn arbitrary_delim() {

#[test]
fn next_float() {
let mut string: &[u8] = b"2.5";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"2.5";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.next_float::<f64>(), Some(2.5));
}

#[test]
fn next_int_custom_radix() {
let mut string: &[u8] = b"11010";
let mut test = Scanner::new(&mut string);
let string: &[u8] = b"11010";
let mut test = Scanner::new(BufReader::new(string));

// invalid radix should return None and not consume `Scanner.next()`
assert_eq!(test.next_int_radix::<i32>(1), None);
Expand All @@ -138,8 +140,8 @@ fn next_int_custom_radix() {

#[test]
fn next_float_base_2() {
let mut string: &[u8] = b"11010.1";
let mut test = Scanner::new(&mut string);
let string: &[u8] = b"11010.1";
let mut test = Scanner::new(BufReader::new(string));

// invalid radix should return None and not consume `Scanner.next()`
assert_eq!(test.next_float_radix::<f64>(1), None);
Expand All @@ -150,8 +152,8 @@ fn next_float_base_2() {

#[test]
fn str_delim_escapes_regexes() {
let mut string: &[u8] = b"foo[a-z]+bar";
let mut test: Scanner = Scanner::new(&mut string);
let string: &[u8] = b"foo[a-z]+bar";
let mut test = Scanner::new(BufReader::new(string));
test.set_delim_str("[a-z]+");

test.next();
Expand All @@ -160,8 +162,8 @@ fn str_delim_escapes_regexes() {

#[test]
fn radix_between_2_36() {
let mut string: &[u8] = b"";
let mut test = Scanner::new(&mut string);
let string: &[u8] = b"";
let mut test = Scanner::new(BufReader::new(string));

assert_eq!(test.get_radix(), 10);
test.set_radix(1);
Expand All @@ -179,8 +181,7 @@ fn radix_between_2_36() {
#[test]
fn buffer_ends_before_delim() {
let string: &[u8] = b"hello world";
let mut br = BufReader::with_capacity(4, string);
let mut test = Scanner::new(&mut br);
let mut test = Scanner::new(BufReader::with_capacity(4, string));

assert_eq!(test.next(), Some(String::from("hello")));
}
Expand All @@ -193,8 +194,7 @@ fn buffer_ends_before_delim() {
#[test]
fn buffer_ends_within_end_delim() {
let string: &[u8] = b"foo bar";
let mut br = BufReader::with_capacity(4, string);
let mut test = Scanner::new(&mut br);
let mut test = Scanner::new(BufReader::with_capacity(4, string));
test.set_delim_str(" ");

assert_eq!(test.next(), Some(String::from("foo")));
Expand All @@ -210,8 +210,7 @@ fn buffer_ends_within_end_delim() {
#[test]
fn buffer_ends_within_start_delim() {
let string: &[u8] = b"aaaabfoo";
let mut br = BufReader::with_capacity(4, string);
let mut test = Scanner::new(&mut br);
let mut test = Scanner::new(BufReader::with_capacity(4, string));
test.set_delim(Regex::new(r"a+b").unwrap());

assert_eq!(test.next(), Some(String::from("foo")));
Expand All @@ -229,8 +228,7 @@ fn buffer_ends_within_start_delim() {
#[test]
fn buffer_boundary_preserves_greed() {
let string: &[u8] = b"aaabbfoo";
let mut br = BufReader::with_capacity(4, string);
let mut test = Scanner::new(&mut br);
let mut test = Scanner::new(BufReader::with_capacity(4, string));
test.set_delim(Regex::new(r"a[ab]*b").unwrap());

// If this test fails, we expect it to produce "bfoo" instead of "foo".
Expand Down

0 comments on commit 36c64a3

Please sign in to comment.