use encoding::{all::GBK, DecoderTrap, Encoding};
use std::{
fmt::{self},
fs,
io::{self, BufRead},
path,
str::{FromStr, SplitWhitespace},
};
mod mi4tool {}
pub struct Mi4Info {
pub date_hour: u32,
pub mtime: u32,
pub lon_step: f64,
pub lat_step: f64,
pub lon_from: f64,
pub lon_to: f64,
pub lat_from: f64,
pub lat_to: f64,
pub width: u32,
pub height: u32,
pub values: Vec<f64>,
}
fn parse_value<V, E>(sv: &mut SplitWhitespace, msg: &str) -> V
where
E: fmt::Debug,
V: FromStr<Err = E>,
{
let v = sv
.next()
.unwrap()
.parse()
.expect(format!("{msg} - {:?}", sv).as_str());
v
}
fn read_mi4info(path: path::PathBuf, date_hour: u32) -> Result<Mi4Info, io::Error> {
let mi4file = fs::File::open(&path)?;
let mut mi4in = io::BufReader::new(mi4file);
let mut buf = vec![];
let end = b'\n';
mi4in.read_until(end, &mut buf)?;
let _: String = GBK.decode(buf.as_ref(), DecoderTrap::Strict).unwrap();
buf.clear();
mi4in.read_until(end, &mut buf)?;
let info = GBK.decode(buf.as_ref(), DecoderTrap::Strict).unwrap();
let strs = &mut info.split_whitespace();
let year: u32 = strs.next().unwrap().parse().expect("Not valid year - ");
let month: u32 = strs.next().unwrap().parse().expect("Not valid month - ");
let day: u32 = strs.next().unwrap().parse().expect("Not valid day - ");
let hour: u32 = strs.next().unwrap().parse().expect("Not valid hour - ");
let mut date_hour = date_hour;
if date_hour > 0 {
} else {
date_hour = year * 1000000 + month * 10000 + day * 100 + hour
}
let mtime: u32 = strs.next().unwrap().parse().expect("Not valid mtime - ");
if mtime == 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"ignore 0 hour forecast",
));
}
let _invalid: f64 = strs.next().unwrap().parse().expect("Not valid invalid - ");
let lon_step: f64 = strs.next().unwrap().parse().expect("Not valid lon step - ");
let lat_step: f64 = strs.next().unwrap().parse().expect("Not valid lat step - ");
let lon_from: f64 = strs.next().unwrap().parse().expect("Not valid lon from - ");
let lon_to: f64 = strs.next().unwrap().parse().expect("Not valid lon to - ");
let lat_from: f64 = strs.next().unwrap().parse().expect("Not valid lat from - ");
let lat_to: f64 = strs.next().unwrap().parse().expect("Not valid lat to - ");
let width: u32 = strs.next().unwrap().parse().expect("Not valid width - ");
let height: u32 = parse_value(strs, "Not valid height - ");
let mut values: Vec<f64> = Vec::new();
mi4in.lines().for_each(|s| {
s.unwrap().split_whitespace().for_each(|v| {
let sv: f64 = v.parse().unwrap();
values.push(sv);
});
});
Ok(Mi4Info {
date_hour,
mtime,
lon_from,
lon_to,
lat_from,
lat_to,
lon_step,
lat_step,
width,
height,
values,
})
}
pub fn read_mi4dir(mi4dir: &str, date_hour: u32) -> Result<Vec<Mi4Info>, io::Error> {
let dir = match fs::read_dir(mi4dir) {
Ok(ls) => ls,
Err(e) => return Err(io::Error::new(e.kind(), e)),
};
let mut tasks = vec![];
let dir = dir.map(|f| f.unwrap());
let mut infos = vec![];
for (_, f) in dir.into_iter().enumerate() {
let path = f.path();
if !path.is_file() {
continue;
}
let t = std::thread::spawn(move || {
return read_mi4info(path, date_hour);
});
tasks.push(t);
}
for t in tasks {
let r = t.join().unwrap();
if r.is_ok() {
infos.push(r.unwrap());
}
}
return Ok(infos);
}