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])
 | |
| } |