nkl/data/endf/read.rs
1use std::io::BufRead;
2
3use super::{
4 parse_endf_integer, parse_float, parse_integer, Cont, EndfError, Intg, List, Tab1, Tab2, Text,
5};
6
7// Maximum endf line length: 80 chars + optional `\r` + `\n`.
8const ENDF_MAX_LINE_LENGTH: usize = 82;
9
10/// Reader specialized for ENDF format files.
11#[derive(Debug)]
12pub struct EndfReader<B: BufRead> {
13 buf: B,
14}
15
16impl<B: BufRead> EndfReader<B> {
17 /// Creates an `EndfReader` from specified source.
18 ///
19 /// # Examples
20 ///
21 /// ```no_run
22 /// use std::fs::File;
23 /// use std::io::BufReader;
24 /// use nkl::data::endf::EndfReader;
25 ///
26 /// let path = "path/to/file.endf";
27 /// let file = File::open(path).expect("could not open endf file");
28 /// let buf_reader = BufReader::new(file);
29 /// let endf_reader = EndfReader::new(buf_reader);
30 /// ```
31 pub fn new(buf: B) -> Self {
32 Self { buf }
33 }
34
35 /// Reads a line from the `EndfReader`.
36 ///
37 /// # Examples
38 ///
39 /// ```no_run
40 /// use std::fs::File;
41 /// use std::io::BufReader;
42 /// use nkl::data::endf::EndfReader;
43 ///
44 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
45 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
46 /// let line = reader.read_line()?;
47 /// # Ok(())
48 /// # }
49 /// ```
50 pub fn read_line(&mut self) -> Result<Vec<u8>, EndfError> {
51 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
52 match self.buf.read_until(b'\n', &mut buf) {
53 Ok(0) => Err(EndfError::EndOfFile),
54 Err(error) => Err(error.into()),
55 Ok(_) => Ok(buf),
56 }
57 }
58
59 /// Reads a **CONT** record from the `EndfReader`.
60 ///
61 /// # Examples
62 ///
63 /// ```no_run
64 /// use std::fs::File;
65 /// use std::io::BufReader;
66 /// use nkl::data::endf::EndfReader;
67 ///
68 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
69 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
70 /// let cont = reader.read_cont()?;
71 /// # Ok(())
72 /// # }
73 /// ```
74 ///
75 /// # Errors
76 ///
77 /// Errors if:
78 /// - I/O error occurs
79 /// - malformed/invalid data
80 pub fn read_cont(&mut self) -> Result<Cont, EndfError> {
81 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
82 match self.buf.read_until(b'\n', &mut buf) {
83 Ok(0) => Err(EndfError::EndOfFile),
84 Err(error) => Err(error.into()),
85 Ok(_) => {
86 let c1 = parse_float(&buf, 1)?;
87 let c2 = parse_float(&buf, 2)?;
88 let l1 = parse_integer(&buf, 3)?;
89 let l2 = parse_integer(&buf, 4)?;
90 let n1 = parse_integer(&buf, 5)?;
91 let n2 = parse_integer(&buf, 6)?;
92 Ok(Cont(c1, c2, l1, l2, n1, n2))
93 }
94 }
95 }
96
97 /// Reads a **INTG** record from the `EndfReader`.
98 ///
99 /// `ndigit` denotes the number of digits for values.
100 ///
101 /// # Examples
102 ///
103 /// ```no_run
104 /// use std::fs::File;
105 /// use std::io::BufReader;
106 /// use nkl::data::endf::EndfReader;
107 ///
108 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
109 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
110 /// let intg = reader.read_intg(2)?;
111 /// # Ok(())
112 /// # }
113 /// ```
114 ///
115 /// # Errors
116 ///
117 /// Errors if:
118 /// - I/O error occurs
119 /// - malformed/invalid data
120 ///
121 /// # Panics
122 ///
123 /// Panics if `ndigit` ∉ `[2, 6]`
124 pub fn read_intg(&mut self, ndigit: usize) -> Result<Intg, EndfError> {
125 assert!(ndigit >= 2);
126 assert!(ndigit <= 6);
127 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
128 match self.buf.read_until(b'\n', &mut buf) {
129 Ok(0) => Err(EndfError::EndOfFile),
130 Err(error) => Err(error.into()),
131 Ok(_) => {
132 let ii = match buf.get(0..5) {
133 Some(slice) => match parse_endf_integer(slice) {
134 Ok(integer) => integer,
135 Err(_) => return Err(EndfError::Data),
136 },
137 None => return Err(EndfError::Format),
138 };
139 let jj = match buf.get(5..10) {
140 Some(slice) => match parse_endf_integer(slice) {
141 Ok(integer) => integer,
142 Err(_) => return Err(EndfError::Data),
143 },
144 None => return Err(EndfError::Format),
145 };
146 let mut kij = Vec::new();
147 let mut ptr = if ndigit <= 5 { 11 } else { 10 };
148 loop {
149 if ptr + ndigit + 1 > 66 {
150 break;
151 }
152 let slice = &buf[ptr..ptr + ndigit + 1];
153 let value = match parse_endf_integer(slice) {
154 Ok(value) => value,
155 Err(_) => return Err(EndfError::Data),
156 };
157 kij.push(value);
158 ptr += ndigit + 1;
159 }
160 Ok(Intg(ii, jj, kij))
161 }
162 }
163 }
164
165 /// Reads a **LIST** record from the `EndfReader`.
166 ///
167 /// # Examples
168 ///
169 /// ```no_run
170 /// use std::fs::File;
171 /// use std::io::BufReader;
172 /// use nkl::data::endf::EndfReader;
173 ///
174 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
175 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
176 /// let list = reader.read_list()?;
177 /// # Ok(())
178 /// # }
179 /// ```
180 ///
181 /// # Errors
182 ///
183 /// Errors if:
184 /// - I/O error occurs
185 /// - malformed/invalid data
186 pub fn read_list(&mut self) -> Result<List, EndfError> {
187 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
188 match self.buf.read_until(b'\n', &mut buf) {
189 Ok(0) => Err(EndfError::EndOfFile),
190 Err(error) => Err(error.into()),
191 Ok(_) => {
192 let c1 = parse_float(&buf, 1)?;
193 let c2 = parse_float(&buf, 2)?;
194 let l1 = parse_integer(&buf, 3)?;
195 let l2 = parse_integer(&buf, 4)?;
196 let npl = parse_integer(&buf, 5)?;
197 let n2 = parse_integer(&buf, 6)?;
198 let npl: usize = match npl.try_into() {
199 Ok(npl) => npl,
200 Err(_) => return Err(EndfError::Data),
201 };
202 let mut b = Vec::with_capacity(npl);
203 while b.len() < npl {
204 buf.clear();
205 match self.buf.read_until(b'\n', &mut buf) {
206 Ok(0) => return Err(EndfError::EndOfFile),
207 Err(error) => return Err(error.into()),
208 Ok(_) => {
209 for col in 0..6 {
210 if b.len() == npl {
211 break;
212 }
213 let float = parse_float(&buf, col + 1)?;
214 b.push(float);
215 }
216 }
217 }
218 }
219 Ok(List(c1, c2, l1, l2, npl, n2, b))
220 }
221 }
222 }
223
224 /// Reads a **TAB1** record from the `EndfReader`.
225 ///
226 /// # Examples
227 ///
228 /// ```no_run
229 /// use std::fs::File;
230 /// use std::io::BufReader;
231 /// use nkl::data::endf::EndfReader;
232 ///
233 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
234 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
235 /// let tab1 = reader.read_tab1()?;
236 /// # Ok(())
237 /// # }
238 /// ```
239 ///
240 /// # Errors
241 ///
242 /// Errors if:
243 /// - I/O error occurs
244 /// - malformed/invalid data
245 pub fn read_tab1(&mut self) -> Result<Tab1, EndfError> {
246 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
247 match self.buf.read_until(b'\n', &mut buf) {
248 Ok(0) => Err(EndfError::EndOfFile),
249 Err(error) => Err(error.into()),
250 Ok(_) => {
251 let c1 = parse_float(&buf, 1)?;
252 let c2 = parse_float(&buf, 2)?;
253 let l1 = parse_integer(&buf, 3)?;
254 let l2 = parse_integer(&buf, 4)?;
255 let nr = parse_integer(&buf, 5)?;
256 let np = parse_integer(&buf, 6)?;
257 let nr: usize = match nr.try_into() {
258 Ok(nr) => nr,
259 Err(_) => return Err(EndfError::Data),
260 };
261 let np: usize = match np.try_into() {
262 Ok(np) => np,
263 Err(_) => return Err(EndfError::Data),
264 };
265 let mut int = Vec::with_capacity(nr);
266 while int.len() < nr {
267 buf.clear();
268 match self.buf.read_until(b'\n', &mut buf) {
269 Ok(0) => return Err(EndfError::EndOfFile),
270 Err(error) => return Err(error.into()),
271 Ok(_) => {
272 for col in 0..3 {
273 if int.len() == nr {
274 break;
275 }
276 let nbt = parse_integer(&buf, 2 * col + 1)?;
277 let nbt: u32 = match nbt.try_into() {
278 Ok(nbt) => nbt,
279 Err(_) => return Err(EndfError::Data),
280 };
281 let scheme = parse_integer(&buf, 2 * col + 2)?;
282 let scheme: usize = match scheme.try_into() {
283 Ok(scheme) => scheme,
284 Err(_) => return Err(EndfError::Data),
285 };
286 int.push((nbt, scheme));
287 }
288 }
289 }
290 }
291 let mut tab = Vec::with_capacity(np);
292 while tab.len() < np {
293 buf.clear();
294 match self.buf.read_until(b'\n', &mut buf) {
295 Ok(0) => return Err(EndfError::EndOfFile),
296 Err(error) => return Err(error.into()),
297 Ok(_) => {
298 for col in 0..3 {
299 if tab.len() == np {
300 break;
301 }
302 let x = parse_float(&buf, 2 * col + 1)?;
303 let y = parse_float(&buf, 2 * col + 2)?;
304 tab.push((x, y));
305 }
306 }
307 }
308 }
309 Ok(Tab1(c1, c2, l1, l2, nr, np, int, tab))
310 }
311 }
312 }
313
314 /// Reads a **TAB2** record from the `EndfReader`.
315 ///
316 /// # Examples
317 ///
318 /// ```no_run
319 /// use std::fs::File;
320 /// use std::io::BufReader;
321 /// use nkl::data::endf::EndfReader;
322 ///
323 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
324 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
325 /// let tab2 = reader.read_tab2()?;
326 /// # Ok(())
327 /// # }
328 /// ```
329 ///
330 /// # Errors
331 ///
332 /// Errors if:
333 /// - I/O error occurs
334 /// - malformed/invalid data
335 pub fn read_tab2(&mut self) -> Result<Tab2, EndfError> {
336 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
337 match self.buf.read_until(b'\n', &mut buf) {
338 Ok(0) => Err(EndfError::EndOfFile),
339 Err(error) => Err(error.into()),
340 Ok(_) => {
341 let c1 = parse_float(&buf, 1)?;
342 let c2 = parse_float(&buf, 2)?;
343 let l1 = parse_integer(&buf, 3)?;
344 let l2 = parse_integer(&buf, 4)?;
345 let nr = parse_integer(&buf, 5)?;
346 let nz = parse_integer(&buf, 6)?;
347 let nr: usize = match nr.try_into() {
348 Ok(nr) => nr,
349 Err(_) => return Err(EndfError::Data),
350 };
351 let nz: usize = match nz.try_into() {
352 Ok(nz) => nz,
353 Err(_) => return Err(EndfError::Data),
354 };
355 let mut int = Vec::with_capacity(nr);
356 while int.len() < nr {
357 buf.clear();
358 match self.buf.read_until(b'\n', &mut buf) {
359 Ok(0) => return Err(EndfError::EndOfFile),
360 Err(error) => return Err(error.into()),
361 Ok(_) => {
362 for col in 0..3 {
363 if int.len() == nr {
364 break;
365 }
366 let nbt = parse_integer(&buf, 2 * col + 1)?;
367 let nbt: u32 = match nbt.try_into() {
368 Ok(nbt) => nbt,
369 Err(_) => return Err(EndfError::Data),
370 };
371 let scheme = parse_integer(&buf, 2 * col + 2)?;
372 let scheme: usize = match scheme.try_into() {
373 Ok(scheme) => scheme,
374 Err(_) => return Err(EndfError::Data),
375 };
376 int.push((nbt, scheme));
377 }
378 }
379 }
380 }
381 Ok(Tab2(c1, c2, l1, l2, nr, nz, int))
382 }
383 }
384 }
385
386 /// Reads a **TEXT** record from the `EndfReader`.
387 ///
388 /// # Examples
389 ///
390 /// ```no_run
391 /// use std::fs::File;
392 /// use std::io::BufReader;
393 /// use nkl::data::endf::EndfReader;
394 ///
395 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
396 /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
397 /// let text = reader.read_text()?;
398 /// # Ok(())
399 /// # }
400 /// ```
401 ///
402 /// # Errors
403 ///
404 /// Errors if:
405 /// - I/O error occurs
406 /// - malformed/invalid data
407 pub fn read_text(&mut self) -> Result<Text, EndfError> {
408 let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
409 match self.buf.read_until(b'\n', &mut buf) {
410 Ok(0) => Err(EndfError::EndOfFile),
411 Err(error) => Err(error.into()),
412 Ok(_) => {
413 let hl = match String::from_utf8(buf[..66].to_vec()) {
414 Ok(string) => string,
415 Err(_) => return Err(EndfError::Data),
416 };
417 Ok(Text(hl))
418 }
419 }
420 }
421}