1use core::fmt;
2use std::str::FromStr;
3
4use color_eyre::{Report, Result};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub enum Unit {
10 Standard,
11 Metric,
12 Imperial,
13}
14
15impl fmt::Display for Unit {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 match self {
18 Unit::Standard => write!(f, "standard"),
19 Unit::Metric => write!(f, "metric"),
20 Unit::Imperial => write!(f, "imperial"),
21 }
22 }
23}
24
25impl FromStr for Unit {
26 type Err = Report;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 match s.to_lowercase().as_str() {
30 "metric" | "c" => Ok(Self::Metric),
31 "standard" | "k" => Ok(Self::Standard),
32 "imperial" | "f" => Ok(Self::Imperial),
33 _ => Err(Report::msg("Invalid unit")),
34 }
35 }
36}
37
38pub async fn get_data(
41 base_url: &str,
42 api_key: &str,
43 location: &str,
44 units: &Unit,
45) -> Result<(String, String)> {
46 let request_url = format!(
47 "{}?appid={}&q={}&units={}",
48 base_url, api_key, location, units
49 );
50 let response = reqwest::get(request_url).await?.text().await?;
51 let data: Value = serde_json::from_str(response.as_str())?;
52 let weather = &data["weather"][0]["description"];
53 let temperature = &data["main"]["temp"];
54 if weather.is_null() || temperature.is_null() {
55 eprintln!("Data for \"{}\" not found", location);
56 Err(Report::msg("Weather data could not be found"))
57 } else {
58 let temp_suffix = match units {
59 Unit::Standard => "⁰K",
60 Unit::Metric => "⁰C",
61 Unit::Imperial => "⁰F",
62 };
63 let mut temp = temperature.to_string();
64 temp.push_str(temp_suffix);
65 Ok((temp, weather.to_string()))
66 }
67}