102 lines
2.7 KiB
Rust
102 lines
2.7 KiB
Rust
use std::fmt::Display;
|
|
use std::fs::File;
|
|
use std::io::{BufReader, Bytes};
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub struct StationMeasurements {
|
|
pub min: isize,
|
|
pub max: isize,
|
|
pub count: isize,
|
|
pub sum: isize,
|
|
}
|
|
|
|
impl StationMeasurements {
|
|
pub fn update(&mut self, v: isize) {
|
|
self.min = self.min.min(v);
|
|
self.max = self.max.max(v);
|
|
self.count += 1;
|
|
self.sum += v;
|
|
}
|
|
|
|
pub fn merge(&mut self, other: &Self) {
|
|
self.min = self.min.min(other.min);
|
|
self.max = self.max.max(other.max);
|
|
self.count += other.count;
|
|
self.sum += other.sum;
|
|
}
|
|
}
|
|
|
|
impl Display for StationMeasurements {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let min = self.min as f64 / 10.0;
|
|
let max = self.max as f64 / 10.0;
|
|
let avg = (self.sum as f64 / self.count as f64) / 10.0;
|
|
write!(f, "{min}/{avg:.1}/{max}")
|
|
}
|
|
}
|
|
|
|
pub fn format_nums(num: usize) -> String {
|
|
num.to_string()
|
|
.as_bytes()
|
|
.rchunks(3)
|
|
.rev()
|
|
.map(std::str::from_utf8)
|
|
.collect::<Result<Vec<&str>, _>>()
|
|
.unwrap()
|
|
.join("_")
|
|
}
|
|
|
|
#[inline]
|
|
pub const fn get_digit(b: u8) -> u32 {
|
|
(b as u32).wrapping_sub('0' as u32)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn parse_temp(bytes: &[u8]) -> isize {
|
|
let is_negative = bytes[0] == b'-';
|
|
let as_decimal = match (is_negative, bytes.len()) {
|
|
(true, 4) => get_digit(bytes[1]) * 10 + get_digit(bytes[3]),
|
|
(true, 5) => get_digit(bytes[1]) * 100 + get_digit(bytes[2]) * 10 + get_digit(bytes[4]),
|
|
(false, 3) => get_digit(bytes[0]) * 10 + get_digit(bytes[2]),
|
|
(false, 4) => get_digit(bytes[0]) * 100 + get_digit(bytes[1]) * 10 + get_digit(bytes[3]),
|
|
_x => panic!("could not parse temp: is_negative = {is_negative}, length = {}", bytes.len()),
|
|
};
|
|
if is_negative {
|
|
-(as_decimal as isize)
|
|
} else {
|
|
as_decimal as isize
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn read_bytes_until(bytes: &mut Bytes<BufReader<&File>>, delimiter: u8) -> Option<[u8; 108]> {
|
|
// 108 max length of line in bytes
|
|
let mut buf: [u8; 108] = [b'#'; 108];
|
|
let mut idx = 0;
|
|
while let Some(byte) = bytes.next() {
|
|
if byte.is_err() {
|
|
panic!("Could not read byte");
|
|
}
|
|
let byte = byte.unwrap();
|
|
if delimiter == byte {
|
|
return Some(buf);
|
|
}
|
|
buf[idx] = byte;
|
|
idx += 1;
|
|
}
|
|
None
|
|
}
|
|
|
|
#[inline]
|
|
pub fn parse_line(line: &[u8]) -> (&[u8], &[u8]) {
|
|
let mut idx = 0;
|
|
while idx < line.len() && line[idx] != b';' {
|
|
idx += 1;
|
|
}
|
|
let station = &line[0..idx];
|
|
let midpoint = idx + 1;
|
|
while idx < line.len() && line[idx] != b'#' {
|
|
idx += 1;
|
|
}
|
|
(station, &line[midpoint..idx])
|
|
} |