rbufr/src/discriptor_table.rs
2025-12-22 22:53:49 +08:00

163 lines
4.5 KiB
Rust

use crate::errors::Result;
use encoding_rs::WINDOWS_1252;
use std::fs;
use std::path::{Path, PathBuf};
mod btable;
mod dtable;
pub use btable::BTable;
pub use dtable::DTable;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TableType {
A,
B,
C,
D,
}
pub struct BUFRTable;
pub trait TableTrait {
fn file_path(table_type: TableType, sub_center: Option<u32>, table_version: u8) -> PathBuf;
}
impl BUFRTable {
pub fn file_path(table_type: TableType, table_version: u8) -> PathBuf {
let base_dir = Path::new("tables/bufr");
let file_name = match table_type {
TableType::A => format!("bufrtaba_{}.csv", table_version),
TableType::B => format!("bufrtabb_{}.csv", table_version),
TableType::C => format!("bufrtabc_{}.csv", table_version),
TableType::D => format!("bufrtabd_{}.csv", table_version),
};
base_dir.join(file_name)
}
}
pub struct LocalTable;
impl LocalTable {
pub fn file_path(table_type: TableType, sub_center: u32, table_version: u8) -> PathBuf {
let base_dir = Path::new("tables/local");
let file_name = match table_type {
TableType::A => format!("loctaba_{}_{}.csv", sub_center * 256, table_version),
TableType::B => format!("loctabb_{}_{}.csv", sub_center * 256, table_version),
TableType::C => format!("loctabc_{}_{}.csv", sub_center * 256, table_version),
TableType::D => format!("loctabd_{}_{}.csv", sub_center * 256, table_version),
};
base_dir.join(file_name)
}
}
impl TableTrait for BUFRTable {
fn file_path(table_type: TableType, sub_center: Option<u32>, table_version: u8) -> PathBuf {
BUFRTable::file_path(table_type, table_version)
}
}
impl TableTrait for LocalTable {
fn file_path(table_type: TableType, sub_center: Option<u32>, table_version: u8) -> PathBuf {
let sub_center = sub_center.expect("Sub-center must be provided for LocalTable");
LocalTable::file_path(table_type, sub_center, table_version)
}
}
#[derive(Debug, Clone)]
pub struct TableLoader<T: TableT> {
sequences: Vec<T::Seq>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TT {
Localized(u32), // sub_center
Standard,
}
impl<T: TableT> TableLoader<T> {
pub fn new() -> Self {
Self {
sequences: Vec::new(),
}
}
pub fn load_table(&mut self, table_type: TT, table_version: u8) -> Result<Vec<T::Seq>> {
let table_kind = T::table_type();
let local_table_path = match table_type {
TT::Localized(sc) => LocalTable::file_path(table_kind, sc, table_version),
TT::Standard => BUFRTable::file_path(table_kind, table_version),
};
// Here you would add code to actually load and parse the table from the file at `path`.
println!("Loading table from path: {:?}", local_table_path);
let raw = fs::read(&local_table_path)?;
let fixed = normalize_dashes(raw);
let text = decode_tabd_text(fixed);
let mut table = T::default();
for line in text.lines() {
if let Some(seq) = table.parse_line(line) {
self.sequences.push(seq);
}
}
if let Some(seq) = table.finish() {
self.sequences.push(seq);
}
let mut sequences = Vec::new();
std::mem::swap(&mut sequences, &mut self.sequences);
Ok(sequences)
}
}
fn normalize_dashes(mut bytes: Vec<u8>) -> Vec<u8> {
for b in &mut bytes {
match *b {
0x96 | 0x97 => *b = b'-', // EN / EM dash → '-'
_ => {}
}
}
bytes
}
fn decode_tabd_text(bytes: Vec<u8>) -> String {
let (text, _, _) = WINDOWS_1252.decode(&bytes);
text.into_owned()
}
pub trait TableT: Default {
type Seq;
fn table_type() -> TableType;
fn parse_line(&mut self, line: &str) -> Option<Self::Seq>;
fn finish(&mut self) -> Option<Self::Seq> {
None
}
}
#[derive(Debug, Clone)]
pub struct Descriptor {
pub f: i32,
pub x: i32,
pub y: i32,
}
#[cfg(test)]
mod test {
use crate::discriptor_table::{TableLoader, btable::BTable, dtable::DTable};
#[test]
fn test_read_table() {
// let mut bufr_table: super::Table<super::BUFRTable> = super::Table::new();
let mut bufr_table = TableLoader::<BTable>::new();
bufr_table.load_table(super::TT::Standard, 11).unwrap();
println!("{:#?}", bufr_table.sequences);
}
}