diff --git a/rust/prop_grid_rs/Cargo.lock b/rust/prop_grid_rs/Cargo.lock index 0c2c0a99..d117e86d 100644 --- a/rust/prop_grid_rs/Cargo.lock +++ b/rust/prop_grid_rs/Cargo.lock @@ -695,12 +695,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" version = "0.4.3" @@ -1266,16 +1260,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.21.4" @@ -1449,14 +1433,10 @@ dependencies = [ name = "prop_grid_rs" version = "0.1.0" dependencies = [ - "anyhow", "axum", - "byteorder", - "bytes", "chrono", "flate2", "futures", - "num_cpus", "png", "pretty_assertions", "prometheus", diff --git a/rust/prop_grid_rs/Cargo.toml b/rust/prop_grid_rs/Cargo.toml index e18773a4..6c5ca489 100644 --- a/rust/prop_grid_rs/Cargo.toml +++ b/rust/prop_grid_rs/Cargo.toml @@ -20,8 +20,6 @@ path = "src/bin/hrrr_point_worker.rs" tokio = { version = "1", features = ["full"] } sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "macros", "json"] } reqwest = { version = "0.13", features = ["rustls", "stream"], default-features = false } -bytes = "1" -anyhow = "1" thiserror = "2" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } @@ -29,8 +27,6 @@ chrono = { version = "0.4", features = ["serde"] } uuid = { version = "1", features = ["v4", "serde"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -num_cpus = "1" -byteorder = "1" futures = "0.3" rayon = "1.12" axum = { version = "0.8", default-features = false, features = ["http1", "tokio"] } diff --git a/rust/prop_grid_rs/src/bin/worker.rs b/rust/prop_grid_rs/src/bin/worker.rs index 41ba6bea..6d7d4252 100644 --- a/rust/prop_grid_rs/src/bin/worker.rs +++ b/rust/prop_grid_rs/src/bin/worker.rs @@ -47,7 +47,11 @@ async fn main() -> Result<(), Box> { let parallelism: usize = std::env::var("PROP_GRID_RS_PARALLELISM") .ok() .and_then(|v| v.parse().ok()) - .unwrap_or_else(num_cpus::get) + .unwrap_or_else(|| { + std::thread::available_parallelism() + .map(|n| n.get()) + .unwrap_or(1) + }) .max(1); // +2 slots over parallelism: each worker holds one connection during // claim/complete transactions; the spare lets NOTIFY and an opportunistic diff --git a/rust/prop_grid_rs/src/decoder.rs b/rust/prop_grid_rs/src/decoder.rs index 0ef74453..f65c04b7 100644 --- a/rust/prop_grid_rs/src/decoder.rs +++ b/rust/prop_grid_rs/src/decoder.rs @@ -15,8 +15,6 @@ use std::process::{Command, Output}; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; -use byteorder::{ByteOrder, LittleEndian}; - use crate::grid::{round3, GridSpec}; const UNDEFINED_VALUE: f32 = 9.999e20; @@ -244,7 +242,9 @@ pub fn parse_lola_binary(bin: &[u8], messages: &[Message], grid_spec: &GridSpec) let lat_key = (lat * 1000.0).round() as i32; for i in 0..nx { let cell_offset = (j * nx + i) * 4; - let value = LittleEndian::read_f32(&chunk[cell_offset..cell_offset + 4]); + let value = f32::from_le_bytes( + chunk[cell_offset..cell_offset + 4].try_into().unwrap(), + ); if value > UNDEFINED_VALUE / 2.0 { continue; } diff --git a/rust/prop_grid_rs/src/nexrad.rs b/rust/prop_grid_rs/src/nexrad.rs index 9638217c..177b94e4 100644 --- a/rust/prop_grid_rs/src/nexrad.rs +++ b/rust/prop_grid_rs/src/nexrad.rs @@ -7,7 +7,6 @@ //! max dBZ in a ~25 km box, matching Elixir's //! `extract_box/5` output field `max_reflectivity_dbz`. -use bytes::Bytes; use chrono::{DateTime, Datelike, Timelike, Utc}; pub const LON_MIN: f64 = -126.0; @@ -136,7 +135,7 @@ pub async fn fetch_frame( if !resp.status().is_success() { return Err(NexradError::Status(resp.status().as_u16())); } - let body: Bytes = resp.bytes().await?; + let body = resp.bytes().await?; let (pixels, width) = decode_n0q_png(&body)?; let obs = points diff --git a/rust/prop_grid_rs/src/scores_file.rs b/rust/prop_grid_rs/src/scores_file.rs index 9560b12e..cd7bc927 100644 --- a/rust/prop_grid_rs/src/scores_file.rs +++ b/rust/prop_grid_rs/src/scores_file.rs @@ -173,7 +173,6 @@ fn clamp_score(s: i32) -> u8 { /// the raw row-major body plus the metadata. Mirrors the Elixir /// `decode/1` sans Access-behavior niceties. pub fn decode(bytes: &[u8]) -> Option { - use byteorder::{ByteOrder, LittleEndian}; if bytes.len() < 4 + 1 + 4 + 8 + 4 + 4 + 4 + 2 + 2 { return None; } @@ -183,13 +182,13 @@ pub fn decode(bytes: &[u8]) -> Option { if bytes[4] != VERSION { return None; } - let band_mhz = LittleEndian::read_u32(&bytes[5..9]); - let valid_time_unix = LittleEndian::read_i64(&bytes[9..17]); - let lat_min = LittleEndian::read_f32(&bytes[17..21]); - let lon_min = LittleEndian::read_f32(&bytes[21..25]); - let step = LittleEndian::read_f32(&bytes[25..29]); - let n_rows = LittleEndian::read_u16(&bytes[29..31]); - let n_cols = LittleEndian::read_u16(&bytes[31..33]); + let band_mhz = u32::from_le_bytes(bytes[5..9].try_into().ok()?); + let valid_time_unix = i64::from_le_bytes(bytes[9..17].try_into().ok()?); + let lat_min = f32::from_le_bytes(bytes[17..21].try_into().ok()?); + let lon_min = f32::from_le_bytes(bytes[21..25].try_into().ok()?); + let step = f32::from_le_bytes(bytes[25..29].try_into().ok()?); + let n_rows = u16::from_le_bytes(bytes[29..31].try_into().ok()?); + let n_cols = u16::from_le_bytes(bytes[31..33].try_into().ok()?); let body_len = (n_rows as usize) * (n_cols as usize); if bytes.len() < 33 + body_len { return None; diff --git a/rust/prop_grid_rs/tests/scorer_golden.rs b/rust/prop_grid_rs/tests/scorer_golden.rs index fb300b70..6f19b45f 100644 --- a/rust/prop_grid_rs/tests/scorer_golden.rs +++ b/rust/prop_grid_rs/tests/scorer_golden.rs @@ -11,7 +11,6 @@ use std::io::{Cursor, Read}; -use byteorder::{LittleEndian, ReadBytesExt}; use prop_grid_rs::{band_config, scorer}; fn opt(v: f64) -> Option { @@ -22,14 +21,26 @@ fn opt(v: f64) -> Option { } } +fn read_exact(r: &mut Cursor<&[u8]>) -> [u8; N] { + let mut buf = [0u8; N]; + r.read_exact(&mut buf).expect("read_exact"); + buf +} + fn read_f64(r: &mut Cursor<&[u8]>) -> f64 { - r.read_f64::().expect("f64") + f64::from_le_bytes(read_exact::<8>(r)) +} + +fn read_u32(r: &mut Cursor<&[u8]>) -> u32 { + u32::from_le_bytes(read_exact::<4>(r)) +} + +fn read_i32(r: &mut Cursor<&[u8]>) -> i32 { + i32::from_le_bytes(read_exact::<4>(r)) } fn read_u8(r: &mut Cursor<&[u8]>) -> u8 { - let mut buf = [0u8; 1]; - r.read_exact(&mut buf).expect("u8"); - buf[0] + read_exact::<1>(r)[0] } #[test] @@ -38,7 +49,7 @@ fn matches_elixir_golden_fixture() { .expect("tests/scores.bincode — run `mix rust.golden` first"); let mut r = Cursor::new(bytes.as_slice()); - let n = r.read_u32::().expect("n_samples"); + let n = read_u32(&mut r); assert!(n > 0, "empty fixture"); let mut mismatches: Vec = Vec::new(); @@ -63,8 +74,8 @@ fn matches_elixir_golden_fixture() { best_duct_band_ghz: opt(read_f64(&mut r)), bulk_richardson: opt(read_f64(&mut r)), }; - let band_mhz = r.read_u32::().expect("band_mhz"); - let expected = r.read_i32::().expect("expected_score"); + let band_mhz = read_u32(&mut r); + let expected = read_i32(&mut r); let band = band_config::get(band_mhz).expect("band in config"); let got = scorer::composite_score(&c, band).score;