griblib_rust 0.1.1

A collection of utilities to convert GRIB2 data file
Documentation
//! # GribLib->Mi4Tool
//!
//! `mi4tool` is a collection of functions to read MICAPS4 data files
//!

use encoding::{all::GBK, DecoderTrap, Encoding};
use std::{
    fmt::{self},
    fs,
    io::{self, BufRead},
    path,
    str::{FromStr, SplitWhitespace},
};
mod mi4tool {}

//#[derive(Clone)]
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,
    })
}

/// Read MICAPS4 text directory infos
/// # Examples
/// ```
/// use griblib_rust::mi4tool;
///
/// let dir = "/data/mi4text/TMP/";
/// let date_hour = 2023021008;
/// let infos = mi4tool::read_mi4dir(dir, date_hour);
/// ```
/// # Errors
/// std::io::Error
///
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);
}