use stream::*;
use str_stream::*;
use std::rc::*;
use std::cmp::Ordering;
pub use std::ops::Range;
pub use syntex_pos::{Span, FileMap};
use syntex_pos::{BytePos, mk_sp};
impl<'a> Stream for &'a Rc<FileMap>
{
type Output = FileMapStream<'a>;
fn stream(self) -> Self::Output {
FileMapStream::new(self)
}
}
#[derive(Clone)]
pub struct FileMapStream<'a>
{
filemap: Rc<FileMap>,
str_stream: StrStream<'a>,
}
impl<'a> FileMapStream<'a>
{
fn new(filemap: &'a Rc<FileMap>) -> Self {
let src = filemap.src.as_ref().unwrap();
FileMapStream::register_lines(filemap, src);
FileMapStream {
filemap: filemap.clone(),
str_stream: (*src).stream()
}
}
fn register_lines(filemap: &Rc<FileMap>, src: &String) {
if filemap.count_lines() == 0 {
let mut byte_pos: u32 = filemap.start_pos.0;
for line in src.lines() {
filemap.next_line(BytePos(byte_pos));
byte_pos += line.len() as u32 + 1;
}
}
}
fn abs_pos(&self) -> BytePos {
self.filemap.start_pos + BytePos(self.str_stream.bytes_offset() as u32)
}
}
impl<'a> Iterator for FileMapStream<'a>
{
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
self.str_stream.next()
}
}
impl<'a> PartialEq for FileMapStream<'a>
{
fn eq(&self, other: &Self) -> bool {
(&self.str_stream).eq(&other.str_stream)
}
}
impl<'a> Eq for FileMapStream<'a> {}
impl<'a> PartialOrd for FileMapStream<'a>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(&self.str_stream).partial_cmp(&other.str_stream)
}
}
impl<'a> Ord for FileMapStream<'a>
{
fn cmp(&self, other: &Self) -> Ordering {
(&self.str_stream).cmp(&other.str_stream)
}
}
impl<'a> Location for FileMapStream<'a>
{
fn location(&self) -> String {
self.str_stream.location()
}
}
impl<'a> CodeSnippet for FileMapStream<'a>
{
fn code_snippet(&self, len_hint: usize) -> String {
self.str_stream.code_snippet(len_hint)
}
}
impl<'a> ConsumePrefix<&'static str> for FileMapStream<'a>
{
fn consume_prefix(&mut self, prefix: &'static str) -> bool {
self.str_stream.consume_prefix(prefix)
}
}
impl<'a> HasNext for FileMapStream<'a>
{
fn has_next(&self) -> bool {
self.str_stream.has_next()
}
}
impl<'a> StreamSpan for Range<FileMapStream<'a>>
{
type Output = Span;
fn stream_span(&self) -> Self::Output {
mk_sp(
self.start.abs_pos(),
self.end.abs_pos()
)
}
}
#[cfg(test)]
mod test {
extern crate syntex_syntax;
use self::syntex_syntax::codemap::CodeMap;
use super::*;
#[test]
fn test_filemap() {
let codemap = CodeMap::new();
let filemap = codemap.new_filemap(format!("fake"), None, format!("A\n\nT\n"));
let mut stream = filemap.stream();
assert_eq!(filemap.count_lines(), 3);
assert!(stream.next() == Some('A'));
assert!(stream.next() == Some('\n'));
assert!(stream.next() == Some('\n'));
assert!(stream.next() == Some('T'));
let mut stream2 = stream.clone();
assert!(stream.next() == Some('\n'));
assert!(stream2.next() == Some('\n'));
assert!(stream.next() == None);
assert!(stream2.next() == None);
}
}