over/parse/
char_stream.rs

1//! Character stream used for parsing.
2
3use std::cell::RefCell;
4use std::fs::File;
5use std::io;
6use std::io::Read;
7use std::iter::Peekable;
8use std::mem;
9use std::rc::Rc;
10use std::str::Chars;
11
12#[derive(Clone, Debug)]
13struct Inner {
14    file: Option<String>,
15    contents: String,
16    stream: Peekable<Chars<'static>>,
17    line: usize,
18    col: usize,
19}
20
21#[derive(Clone, Debug)]
22pub struct CharStream {
23    inner: Rc<RefCell<Inner>>,
24}
25
26impl CharStream {
27    pub fn from_file(path: &str) -> io::Result<CharStream> {
28        let mut file = File::open(path)?;
29
30        let len = file.metadata()?.len();
31        let mut contents = String::with_capacity(len as usize);
32
33        file.read_to_string(&mut contents)?;
34
35        Self::from_string_impl(Some(String::from(path)), contents)
36    }
37
38    pub fn from_string(contents: String) -> io::Result<CharStream> {
39        Self::from_string_impl(None, contents)
40    }
41
42    fn from_string_impl(file: Option<String>, contents: String) -> io::Result<CharStream> {
43        let chars: Chars = unsafe { mem::transmute(contents.chars()) };
44        let stream = chars.peekable();
45
46        Ok(CharStream {
47            inner: Rc::new(RefCell::new(Inner {
48                file,
49                contents,
50                stream,
51                line: 1,
52                col: 1,
53            })),
54        })
55    }
56
57    pub fn peek(&self) -> Option<char> {
58        let mut inner = self.inner.borrow_mut();
59        let opt = inner.stream.peek();
60
61        match opt {
62            Some(ch) => Some(*ch),
63            None => None,
64        }
65    }
66
67    pub fn file(&self) -> Option<String> {
68        let inner = self.inner.borrow();
69        inner.file.clone()
70    }
71
72    pub fn line(&self) -> usize {
73        let inner = self.inner.borrow();
74        inner.line
75    }
76
77    pub fn col(&self) -> usize {
78        let inner = self.inner.borrow();
79        inner.col
80    }
81
82    fn set_line(&mut self, value: usize) {
83        let mut inner = self.inner.borrow_mut();
84        inner.line = value;
85    }
86
87    fn set_col(&mut self, value: usize) {
88        let mut inner = self.inner.borrow_mut();
89        inner.col = value;
90    }
91}
92
93impl Iterator for CharStream {
94    type Item = char;
95
96    fn next(&mut self) -> Option<Self::Item> {
97        let opt = {
98            let mut inner = self.inner.borrow_mut();
99            inner.stream.next()
100        };
101
102        match opt {
103            Some(ch) => {
104                if ch == '\n' {
105                    let line = self.line();
106                    self.set_line(line + 1);
107                    self.set_col(1);
108                } else {
109                    let col = self.col();
110                    self.set_col(col + 1);
111                }
112                Some(ch)
113            }
114            None => None,
115        }
116    }
117}