1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Buffered Reader wrapper, for efficient data reading.
use std::io::{BufRead, BufReader, Error as IoError, Read};
// Modify this value to update the internal buffer depth.
// RINEX is \n termination based, and always made of rather short lines (about 512 is reasonnable).
// So the proposed value should be more than enough.
const BUF_SIZE: usize = 2048;
/// [Reader] is dedicated to efficient RINEX input parsing.
/// Whether they are local files or not. It implements efficient
/// internal buffering that is specifically scaled for RINEX content.
/// It is solely here to provide [BufRead] implementation on [Read]able interfaces.
pub struct Reader<R: Read> {
/// Internal buffer, which needs to store up to two complete lines.
/// Since the objective here is to always provide a complete Line (without \n termination),
/// and be consistent with std::Lines iterator.
/// RINEX lines are short, and this will be more than enough.
buf: [u8; BUF_SIZE],
rd_ptr: usize,
wr_ptr: usize,
reader: R,
}
impl<R: Read> Reader<R> {
pub fn new(reader: R) -> Self {
Self {
reader,
wr_ptr: 0,
rd_ptr: 0,
buf: [0; BUF_SIZE],
}
}
}
impl<R: Read> Read for Reader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
// always try to pull new content, if we can
let avail = BUF_SIZE - self.wr_ptr;
if avail > 0 {
let size = self.reader.read(&mut self.buf[self.wr_ptr..])?;
self.wr_ptr += size;
}
// try to provide new content if possible
let buf_len = buf.len();
let avail = BUF_SIZE - self.rd_ptr;
if avail < buf_len {
// we have less than buffer can accept:
// return everything we have
buf[..avail].copy_from_slice(&self.buf[self.rd_ptr..]);
Ok(avail)
} else {
// we have more than buffer can accept
// return only what it can accept, avoiding overflow
buf.copy_from_slice(&self.buf[self.rd_ptr..self.rd_ptr + buf_len]);
Ok(buf_len)
}
}
}
impl<R: Read> BufRead for Reader<R> {
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
let avail = BUF_SIZE - self.wr_ptr;
if avail > 0 {
let size = self.reader.read(&mut self.buf[self.wr_ptr..])?;
self.wr_ptr += size;
}
Ok(&self.buf[self.rd_ptr..])
}
fn consume(&mut self, s: usize) {
let avail = 8192 - self.rd_ptr;
if avail >= s {
self.rd_ptr += s;
} else {
self.rd_ptr = 8192;
}
}
}
#[cfg(test)]
mod test {
use super::Reader;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
#[test]
fn v3_lines_iter() {
let mut last_passed = false;
let fd = File::open("../data/OBS/V3/DUTH0630.22O").unwrap();
let reader = BufReader::new(fd);
for (nth, line) in reader.lines().enumerate() {
if let Ok(line) = line {
println!("LINE \"{}\"", line);
if nth == 0 {
assert_eq!(line, " 3.02 OBSERVATION DATA M: MIXED RINEX VERSION / TYPE");
} else if nth == 1 {
assert_eq!(
line,
"HEADER CHANGED BY EPN CB ON 2022-03-11 COMMENT"
);
} else if nth == 34 {
assert_eq!(
line,
" END OF HEADER"
);
} else if nth == 89 {
assert_eq!(line, "R24 20147683.700 107738728.87108 -2188.113 51.000 20147688.700 83796794.50808 -1701.871 48.500");
last_passed = true;
} else {
if nth > 89 {
panic!("producing more than expected!");
}
}
}
}
assert!(last_passed);
}
#[test]
fn v3_lengthy_lines_iter() {
let mut last_passed = false;
let fd = File::open("../data/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz").unwrap();
let reader = Reader::new(fd);
for (nth, line) in reader.lines().enumerate() {
if let Ok(line) = line {
if nth == 0 {
assert_eq!(line, "3.0 COMPACT RINEX FORMAT CRINEX VERS / TYPE");
} else if nth == 1 {
assert_eq!(line, "RNX2CRX ver.4.0.8 06-Jul-22 13:22 CRINEX PROG / DATE");
} else if nth == 56 {
assert_eq!(
line,
" END OF HEADER"
);
} else if nth == 136615 {
assert_eq!(line, "-14156 -3697 936 250");
last_passed = true;
} else {
if nth > 89 {
panic!("producing more than expected!");
}
}
}
}
assert!(last_passed);
}
}