obeli_sk_boa_parser/source/
mod.rs1use std::{
4 fs::File,
5 io::{self, BufReader, Read},
6 path::Path,
7};
8
9pub use utf8::UTF8Input;
10pub use utf16::UTF16Input;
11
12mod utf16;
13mod utf8;
14
15#[derive(Debug)]
20pub struct Source<'path, R> {
21 pub(crate) reader: R,
22 pub(crate) path: Option<&'path Path>,
23}
24
25impl<'bytes> Source<'static, UTF8Input<&'bytes [u8]>> {
26 pub fn from_bytes<T: AsRef<[u8]> + ?Sized>(source: &'bytes T) -> Self {
40 Self {
41 reader: UTF8Input::new(source.as_ref()),
42 path: None,
43 }
44 }
45}
46
47impl<'input> Source<'static, UTF16Input<'input>> {
48 #[must_use]
61 pub fn from_utf16(input: &'input [u16]) -> Self {
62 Self {
63 reader: UTF16Input::new(input),
64 path: None,
65 }
66 }
67}
68
69impl<'path> Source<'path, UTF8Input<BufReader<File>>> {
70 pub fn from_filepath(source: &'path Path) -> io::Result<Self> {
88 let reader = File::open(source)?;
89 Ok(Self {
90 reader: UTF8Input::new(BufReader::new(reader)),
91 path: Some(source),
92 })
93 }
94}
95
96impl<'path, R: Read> Source<'path, UTF8Input<R>> {
97 pub fn from_reader(reader: R, path: Option<&'path Path>) -> Self {
116 Self {
117 reader: UTF8Input::new(reader),
118 path,
119 }
120 }
121}
122
123impl<'path, R> Source<'path, R> {
124 pub fn with_path(self, new_path: &Path) -> Source<'_, R> {
126 Source {
127 reader: self.reader,
128 path: Some(new_path),
129 }
130 }
131
132 pub fn path(&self) -> Option<&'path Path> {
134 self.path
135 }
136}
137
138pub trait ReadChar {
140 fn next_char(&mut self) -> io::Result<Option<u32>>;
146}
147
148#[cfg(test)]
149mod tests {
150 use std::io::Cursor;
151
152 use super::*;
153
154 #[test]
155 fn from_bytes() {
156 let mut source = Source::from_bytes("'Hello' + 'World';");
157
158 assert!(source.path.is_none());
159
160 let mut content = String::new();
161 while let Some(c) = source.reader.next_char().unwrap() {
162 content.push(char::from_u32(c).unwrap());
163 }
164
165 assert_eq!(content, "'Hello' + 'World';");
166 }
167
168 #[test]
169 fn from_filepath() {
170 let manifest_path = Path::new(env!("CARGO_MANIFEST_DIR"));
171 let filepath = manifest_path.join("src/parser/tests/test.js");
172 let mut source = Source::from_filepath(&filepath).unwrap();
173
174 assert_eq!(source.path, Some(&*filepath));
175
176 let mut content = String::new();
177 while let Some(c) = source.reader.next_char().unwrap() {
178 content.push(char::from_u32(c).unwrap());
179 }
180
181 assert_eq!(content, "\"Hello\" + \"World\";\n");
182 }
183
184 #[test]
185 fn from_reader() {
186 let mut source = Source::from_reader(Cursor::new("'Hello' + 'World';"), None);
188
189 assert!(source.path.is_none());
190
191 let mut content = String::new();
192 while let Some(c) = source.reader.next_char().unwrap() {
193 content.push(char::from_u32(c).unwrap());
194 }
195
196 assert_eq!(content, "'Hello' + 'World';");
197
198 let mut source =
200 Source::from_reader(Cursor::new("'Hello' + 'World';"), Some("test.js".as_ref()));
201
202 assert_eq!(source.path, Some("test.js".as_ref()));
203
204 let mut content = String::new();
205 while let Some(c) = source.reader.next_char().unwrap() {
206 content.push(char::from_u32(c).unwrap());
207 }
208
209 assert_eq!(content, "'Hello' + 'World';");
210 }
211}