extern crate rustc_serialize;
use std::io::{ Read };
use std::iter::Iterator;
use rustc_serialize::json::{ Json, Builder };
use std::error::Error;
use std::{ fmt, io, result, str };
pub struct Iter<R> {
inner: R
}
impl<R: Read> Iter<R> {
pub fn new(inner: R) -> Iter<R> {
Iter { inner: inner }
}
}
impl<R: Read> Iterator for Iter<R> {
type Item = Json;
fn next(&mut self) -> Option<Json> {
let ref mut inner = self.inner;
let mut chars = Chars { inner: inner };
let mut buf = String::new();
while let Some(Ok(c)) = chars.next() {
buf.push(c);
match c {
'}' | ']' =>
match Builder::new(buf.chars()).build() {
Ok(j) => return Some(j),
_ => ()
},
_ => ()
}
}
None
}
}
static UTF8_CHAR_WIDTH: [u8; 256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, ];
#[inline]
fn utf8_char_width(b: u8) -> usize {
return UTF8_CHAR_WIDTH[b as usize] as usize;
}
struct Chars<R> {
inner: R,
}
#[derive(Debug)]
enum CharsError {
NotUtf8,
Other(io::Error),
}
impl<R: Read> Iterator for Chars<R> {
type Item = result::Result<char, CharsError>;
fn next(&mut self) -> Option<result::Result<char, CharsError>> {
let mut buf = [0];
let first_byte = match self.inner.read(&mut buf) {
Ok(0) => return None,
Ok(..) => buf[0],
Err(e) => return Some(Err(CharsError::Other(e))),
};
let width = utf8_char_width(first_byte);
if width == 1 { return Some(Ok(first_byte as char)) }
if width == 0 { return Some(Err(CharsError::NotUtf8)) }
let mut buf = [first_byte, 0, 0, 0];
{
let mut start = 1;
while start < width {
match self.inner.read(&mut buf[start..width]) {
Ok(0) => return Some(Err(CharsError::NotUtf8)),
Ok(n) => start += n,
Err(e) => return Some(Err(CharsError::Other(e))),
}
}
}
Some(match str::from_utf8(&buf[..width]).ok() {
Some(s) => {
let v: Vec<char> = s.chars().collect();
Ok(v[0])
},
None => Err(CharsError::NotUtf8),
})
}
}
impl Error for CharsError {
fn description(&self) -> &str {
match *self {
CharsError::NotUtf8 => "invalid utf8 encoding",
CharsError::Other(ref e) => Error::description(e),
}
}
fn cause(&self) -> Option<&Error> {
match *self {
CharsError::NotUtf8 => None,
CharsError::Other(ref e) => e.cause(),
}
}
}
impl fmt::Display for CharsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CharsError::NotUtf8 => {
"byte stream did not contain valid utf8".fmt(f)
}
CharsError::Other(ref e) => e.fmt(f),
}
}
}
#[cfg(test)]
mod tests {
use super::Iter;
#[cfg(feature = "nightly")]
use test::Bencher;
use std::io::{ empty, BufReader };
#[test]
fn test_not_json_iter() {
let reader = BufReader::new("bogus".as_bytes());
assert_eq!(Iter::new(reader).count(), 0);
}
#[test]
fn test_empty_iter() {
assert_eq!(Iter::new(empty()).count(), 0);
}
#[test]
fn test_ary_iter() {
let reader = BufReader::new("[][]".as_bytes());
assert_eq!(Iter::new(reader).count(), 2)
}
#[test]
fn test_obj_iter() {
let reader = BufReader::new("{}{}".as_bytes());
assert_eq!(Iter::new(reader).count(), 2)
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_iter(b: &mut Bencher) {
b.iter(|| Iter::new(BufReader::new("{'foo':'bar'}{'foo':'baz'}".as_bytes())).count())
}
}