Skip to content

Commit

Permalink
Fixed the last pedantic clippy lints.
Browse files Browse the repository at this point in the history
  • Loading branch information
RRArny committed Oct 13, 2024
1 parent 6e31dd0 commit 9052867
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Console utility for accessing aviation weather information from the command line

If you provide no flags to WXfetch at all, it will try and fetch weather info from your closest airfield according to your IP based position (geoip).

With `-a` you can provide the ICAO or IATA code for a reporting station. Alternatively, with `--lat` and `--lon` you can provide geographical coordinates. WXfetch will then try and find a reporting station close to that position. Please make sure to provide both parameters.
With `-a` or `--airfield` you can provide the ICAO or IATA code for a reporting station. Alternatively, with `--lat` and `--lon` you can provide geographical coordinates. WXfetch will then try and find a reporting station close to that position. Please make sure to provide both parameters.

If there is any problem with the provided arguments WXfetch will print an error message and default to geoip.

Expand Down
2 changes: 1 addition & 1 deletion src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ async fn get_nearest_station(config: &Config, secrets: &Secrets) -> Option<Strin
Some(station.to_string())
}

/// For a given ICAO code as String and the necessary Secrets makes request to AvWx to check if the code is valid.
/// For a given ICAO code as String and the necessary Secrets makes request to avwx to check if the code is valid.
pub async fn check_icao_code(icao: &String, secrets: &Secrets) -> bool {
let uri = format!("https://avwx.rest/api/station/{icao}");

Expand Down
77 changes: 38 additions & 39 deletions src/metar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Metar {
/// ICAO code of the issuing station.
icao_code: String,
/// Contents of the report.
fields: Vec<MetarField>,
fields: Vec<WxField>,
/// True, if this METAR was issued by the exact station that was requested, false otherwise.
exact_match: bool,
// / Units.
Expand All @@ -31,7 +31,7 @@ pub struct Metar {

#[derive(PartialEq, Eq, Debug)]
/// Elements of a METAR report.
pub enum MetarField {
pub enum WxField {
/// Issue time.
TimeStamp(DateTime<FixedOffset>),
/// Prevailing winds.
Expand Down Expand Up @@ -61,31 +61,29 @@ pub enum MetarField {
Remarks(String),
}

impl MetarField {
impl WxField {
pub fn colourise(&self) -> ColoredString {
match self {
MetarField::Visibility(vis) => colourise_visibility(*vis),
MetarField::TimeStamp(datetime) => colourize_timestamp(datetime),
MetarField::Wind {
WxField::Visibility(vis) => colourise_visibility(*vis),
WxField::TimeStamp(datetime) => colourize_timestamp(datetime),
WxField::Wind {
direction,
strength,
gusts,
unit,
} => colourise_wind(*direction, *strength, *gusts, *unit),
MetarField::WindVariability { low_dir, hi_dir } => {
colourise_wind_var(*low_dir, *hi_dir)
}
MetarField::Temperature {
WxField::WindVariability { low_dir, hi_dir } => colourise_wind_var(*low_dir, *hi_dir),
WxField::Temperature {
temp,
dewpoint,
unit,
} => colourise_temperature(*temp, *dewpoint, *unit),
MetarField::Qnh(qnh, unit) => colourise_qnh(*qnh, *unit),
MetarField::WxCode(code, intensity, proximity, descriptor) => {
WxField::Qnh(qnh, unit) => colourise_qnh(*qnh, *unit),
WxField::WxCode(code, intensity, proximity, descriptor) => {
colourise_wx_code(code, intensity, proximity, descriptor)
}
MetarField::Remarks(str) => str.black().on_white(),
MetarField::Clouds(cloud, alt) => colourise_clouds(cloud, *alt),
WxField::Remarks(str) => str.black().on_white(),
WxField::Clouds(cloud, alt) => colourise_clouds(cloud, *alt),
}
}
}
Expand Down Expand Up @@ -123,7 +121,7 @@ fn colourise_wx_code(
let intensitystr = format!("{intensity}").color(match intensity {
WxCodeIntensity::Light => Color::BrightGreen,
WxCodeIntensity::Heavy => Color::BrightRed,
_ => Color::White,
WxCodeIntensity::Moderate => Color::White,
});

let descrstr = format!("{descriptor}").color(match descriptor {
Expand Down Expand Up @@ -230,7 +228,7 @@ impl Metar {

let units: Units = Units::from_json(json);

let mut fields: Vec<MetarField> = Vec::new();
let mut fields: Vec<WxField> = Vec::new();

if let Some(time) = get_timestamp(json) {
fields.push(time);
Expand Down Expand Up @@ -288,39 +286,40 @@ impl Metar {
}
}

fn get_remarks(json: &Value) -> Option<MetarField> {
fn get_remarks(json: &Value) -> Option<WxField> {
let rmks = json.get("remarks")?.as_str()?.to_string();
Some(MetarField::Remarks(rmks))
Some(WxField::Remarks(rmks))
}

fn get_timestamp(json: &Value) -> Option<MetarField> {
fn get_timestamp(json: &Value) -> Option<WxField> {
let datetime_str = json.get("time")?.get("dt")?.as_str()?;
let datetime = DateTime::parse_from_rfc3339(datetime_str).ok()?;
Some(MetarField::TimeStamp(datetime))
Some(WxField::TimeStamp(datetime))
}

fn get_qnh(json: &Value, units: Units) -> Option<MetarField> {
#[allow(clippy::cast_possible_truncation)]
fn get_qnh(json: &Value, units: Units) -> Option<WxField> {
let qnh_val: &Value = json.get("altimeter")?.get("value")?;
let qnh: i64 = if qnh_val.is_f64() {
qnh_val.as_f64()?.mul(100.).round() as i64
} else {
qnh_val.as_i64()?
};

Some(MetarField::Qnh(qnh, units.pressure))
Some(WxField::Qnh(qnh, units.pressure))
}

fn get_temp(json: &Value, units: Units) -> Option<MetarField> {
fn get_temp(json: &Value, units: Units) -> Option<WxField> {
let temp = json.get("temperature")?.get("value")?.as_i64()?;
let dewpoint = json.get("dewpoint")?.get("value")?.as_i64()?;
Some(MetarField::Temperature {
Some(WxField::Temperature {
temp,
dewpoint,
unit: units.temperature,
})
}

fn get_wind_var(json: &Value) -> Option<MetarField> {
fn get_wind_var(json: &Value) -> Option<WxField> {
let wind_dirs = json.get("wind_variable_direction")?.as_array()?;
let mut dirs: Vec<i64> = Vec::new();
for dir in wind_dirs {
Expand All @@ -329,13 +328,13 @@ fn get_wind_var(json: &Value) -> Option<MetarField> {
dirs.sort_unstable();
let low_dir = dirs.first()?;
let hi_dir = dirs.last()?;
Some(MetarField::WindVariability {
Some(WxField::WindVariability {
low_dir: *low_dir,
hi_dir: *hi_dir,
})
}

fn get_winds(json: &Value, units: Units) -> Option<MetarField> {
fn get_winds(json: &Value, units: Units) -> Option<WxField> {
let direction = json.get("wind_direction")?.get("value")?.as_i64()?;
let strength = json.get("wind_speed")?.get("value")?.as_i64()?;
let gusts = json
Expand All @@ -344,17 +343,17 @@ fn get_winds(json: &Value, units: Units) -> Option<MetarField> {
.and_then(serde_json::Value::as_i64)
.unwrap_or(0);

Some(MetarField::Wind {
Some(WxField::Wind {
direction,
strength,
gusts,
unit: units.wind_speed,
})
}

fn get_visibility(json: &Value, _units: Units) -> Option<MetarField> {
fn get_visibility(json: &Value, _units: Units) -> Option<WxField> {
let vis = json.get("visibility")?.get("value")?.as_i64()?;
Some(MetarField::Visibility(vis))
Some(WxField::Visibility(vis))
}

fn is_exact_match(station: &str, config: &Config) -> bool {
Expand Down Expand Up @@ -390,7 +389,7 @@ mod tests {
};
let expected = DateTime::parse_from_rfc3339("2024-06-21T05:50:00Z").unwrap();
let metar = Metar::from_json(&json, &config);
assert!(metar.is_some_and(|m| m.fields.contains(&MetarField::TimeStamp(expected))));
assert!(metar.is_some_and(|m| m.fields.contains(&WxField::TimeStamp(expected))));
}

#[test]
Expand Down Expand Up @@ -446,7 +445,7 @@ mod tests {
#[test]
fn test_get_winds() {
let json: Value = Value::from_str("{\"wind_direction\": {\"value\":100}, \"wind_speed\":{\"value\":10}, \"wind_gust\":{\"value\":15}}").unwrap();
let expected = MetarField::Wind {
let expected = WxField::Wind {
direction: 100,
strength: 10,
gusts: 15,
Expand All @@ -461,7 +460,7 @@ mod tests {
let json: Value =
Value::from_str("{\"wind_direction\": {\"value\":100}, \"wind_speed\":{\"value\":10}}")
.unwrap();
let expected = MetarField::Wind {
let expected = WxField::Wind {
direction: 100,
strength: 10,
gusts: 0,
Expand All @@ -474,15 +473,15 @@ mod tests {
#[test]
fn test_get_qnh() {
let json: Value = Value::from_str("{\"altimeter\":{\"value\": 1013}}").unwrap();
let expected = MetarField::Qnh(1013, PressureUnit::Hpa);
let expected = WxField::Qnh(1013, PressureUnit::Hpa);
let actual = get_qnh(&json, Units::default());
assert!(actual.is_some_and(|q| q == expected));
}

#[test]
fn test_get_qnh_inhg() {
let json: Value = Value::from_str("{\"altimeter\":{\"value\": 29.92}}").unwrap();
let expected = MetarField::Qnh(2992, PressureUnit::Inhg);
let expected = WxField::Qnh(2992, PressureUnit::Inhg);
let units = Units {
pressure: PressureUnit::Inhg,
altitude: AltitudeUnit::Ft,
Expand All @@ -500,15 +499,15 @@ mod tests {
let json: Value = Value::from_str("{\"remarks\":\"RWY UNAVAILABLE\"}").unwrap();
let expected = "RWY UNAVAILABLE".to_string();
let actual = get_remarks(&json);
assert!(actual.is_some_and(|r| r == MetarField::Remarks(expected)));
assert!(actual.is_some_and(|r| r == WxField::Remarks(expected)));
}

#[test]
fn test_get_temp() {
let json: Value =
Value::from_str("{\"temperature\":{\"value\": 10}, \"dewpoint\":{\"value\": 9}}")
.unwrap();
let expected: MetarField = MetarField::Temperature {
let expected: WxField = WxField::Temperature {
temp: 10,
dewpoint: 9,
unit: TemperatureUnit::C,
Expand All @@ -522,7 +521,7 @@ mod tests {
let json: Value =
Value::from_str("{\"wind_variable_direction\":[{\"value\" : 80},{\"value\" : 150}]}")
.unwrap();
let expected: MetarField = MetarField::WindVariability {
let expected: WxField = WxField::WindVariability {
low_dir: 80,
hi_dir: 150,
};
Expand All @@ -533,7 +532,7 @@ mod tests {
#[test]
fn test_get_visibility() {
let json: Value = Value::from_str("{\"visibility\":{\"value\":9999}}").unwrap();
let expected: MetarField = MetarField::Visibility(9999);
let expected: WxField = WxField::Visibility(9999);
let actual = get_visibility(&json, Units::default());
assert!(actual.is_some_and(|v| v == expected));
}
Expand Down
24 changes: 12 additions & 12 deletions src/metar/clouds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{fmt::Display, str::FromStr};

use super::MetarField;
use super::WxField;
use anyhow::anyhow;
use regex::Regex;
use serde_json::Value;
Expand All @@ -23,8 +23,8 @@ pub enum Clouds {
}

/// Parses a METAR in JSON form and returns a `Vec` of `MetarField::Clouds` describing the cloud information contained.
pub fn get_clouds_from_json(json: &Value) -> Vec<MetarField> {
let mut result: Vec<MetarField> = Vec::new();
pub fn get_clouds_from_json(json: &Value) -> Vec<WxField> {
let mut result: Vec<WxField> = Vec::new();
if let Some(wxcodes) = json.get("clouds").and_then(|x| x.as_array()) {
for code in wxcodes {
if let Some(repr) = code.get("repr").and_then(|x| x.as_str()) {
Expand All @@ -38,14 +38,14 @@ pub fn get_clouds_from_json(json: &Value) -> Vec<MetarField> {
}

/// From a METAR compliant cloud code representation string (`&str`) parses a `MetarField::Cloud`.
fn clouds_from_str(repr: &str) -> Option<MetarField> {
fn clouds_from_str(repr: &str) -> Option<WxField> {
let regex = format!("(?<obscuration>{})(?<level>\\d*)", Clouds::get_regex());
let regex = Regex::new(&regex)
.expect("Creating RegEx pattern failed. This is likely a software bug, please report it.");
let matches = regex.captures(repr)?;
let obscuration: Clouds = matches["obscuration"].parse().ok()?;
let level: i64 = matches["level"].parse().unwrap_or(0);
Some(MetarField::Clouds(obscuration, level))
Some(WxField::Clouds(obscuration, level))
}

impl Clouds {
Expand Down Expand Up @@ -97,7 +97,7 @@ mod tests {

use serde_json::Value;

use crate::metar::MetarField;
use crate::metar::WxField;

use super::{clouds_from_str, get_clouds_from_json, Clouds};

Expand All @@ -110,14 +110,14 @@ mod tests {

#[test]
fn test_clouds_from_str() {
let expected = MetarField::Clouds(Clouds::Skc, 0);
let expected = WxField::Clouds(Clouds::Skc, 0);
let actual = clouds_from_str("SKC");
assert_eq!(Some(expected), actual);
}

#[test]
fn test_clouds_from_str_sct() {
let expected = MetarField::Clouds(Clouds::Sct, 50);
let expected = WxField::Clouds(Clouds::Sct, 50);
let actual = clouds_from_str("SCT50");
assert_eq!(Some(expected), actual);
}
Expand All @@ -128,10 +128,10 @@ mod tests {
"{\"clouds\":[{\"repr\": \"SCT050\"},{\"repr\": \"BRK100\"},{\"repr\": \"OVC200\"}]}",
)
.unwrap();
let expected: Vec<MetarField> = vec![
MetarField::Clouds(Clouds::Sct, 50),
MetarField::Clouds(Clouds::Brk, 100),
MetarField::Clouds(Clouds::Ovc, 200),
let expected: Vec<WxField> = vec![
WxField::Clouds(Clouds::Sct, 50),
WxField::Clouds(Clouds::Brk, 100),
WxField::Clouds(Clouds::Ovc, 200),
];
let actual = get_clouds_from_json(&json);
assert_eq!(expected, actual);
Expand Down
14 changes: 7 additions & 7 deletions src/metar/wxcodes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::MetarField;
use super::WxField;
use anyhow::{anyhow, Error};
use regex::Regex;
use serde_json::Value;
Expand Down Expand Up @@ -294,7 +294,7 @@ impl Display for WxCodeDescription {
}
}

pub(crate) fn wxcode_from_str(repr: &str) -> Option<MetarField> {
pub(crate) fn wxcode_from_str(repr: &str) -> Option<WxField> {
let regex_pattern = format!(
r"(?<intensity>({})?)(?<descr>({})?)(?<code>{})(?<location>({})?)",
WxCodeIntensity::get_regex(),
Expand All @@ -310,11 +310,11 @@ pub(crate) fn wxcode_from_str(repr: &str) -> Option<MetarField> {
let descriptor: WxCodeDescription = matches["descr"].parse().ok()?;
let proximity: WxCodeProximity = matches["location"].parse().ok()?;

Some(MetarField::WxCode(code, intensity, proximity, descriptor))
Some(WxField::WxCode(code, intensity, proximity, descriptor))
}

pub fn get_wxcodes_from_json(json: &Value) -> Vec<MetarField> {
let mut result: Vec<MetarField> = Vec::new();
pub fn get_wxcodes_from_json(json: &Value) -> Vec<WxField> {
let mut result: Vec<WxField> = Vec::new();
if let Some(wxcodes) = json.get("wx_codes").and_then(|x| x.as_array()) {
for code in wxcodes {
if let Some(repr) = code.get("repr").and_then(|x| x.as_str()) {
Expand All @@ -333,7 +333,7 @@ mod tests {
use std::str::FromStr;

use super::{get_wxcodes_from_json, WxCode, WxCodeIntensity};
use crate::metar::{MetarField, WxCodeProximity};
use crate::metar::{WxCodeProximity, WxField};

#[test]
fn test_get_regex() {
Expand All @@ -358,7 +358,7 @@ mod tests {

#[test]
fn test_get_wxcodes_one() {
let expected: Vec<MetarField> = vec![MetarField::WxCode(
let expected: Vec<WxField> = vec![WxField::WxCode(
WxCode::Ra,
WxCodeIntensity::Light,
WxCodeProximity::OnStation,
Expand Down

0 comments on commit 9052867

Please sign in to comment.