openmeteo-rs 1.0.0

Rust client for the Open-Meteo weather API.
Documentation
use std::fmt::Display;

use reqwest::Url;

use crate::query::{AsApiStr, join_api_values};
use crate::{Error, Result};

pub(crate) type QueryParam = (&'static str, String);

pub(crate) fn build_endpoint_url(
    base: &Url,
    base_field: &'static str,
    path: &str,
    api_key: Option<&str>,
    params: Vec<QueryParam>,
) -> Result<Url> {
    let base_query = base.query().map(str::to_owned);
    let mut url = base.join(path).map_err(|err| Error::InvalidParam {
        field: base_field,
        reason: err.to_string(),
    })?;
    url.set_query(base_query.as_deref());

    {
        let mut pairs = url.query_pairs_mut();
        for (field, value) in params {
            pairs.append_pair(field, &value);
        }
        if let Some(api_key) = api_key {
            pairs.append_pair("apikey", api_key);
        }
    }

    Ok(url)
}

pub(crate) fn push_api_values<T>(params: &mut Vec<QueryParam>, field: &'static str, values: &[T])
where
    T: AsApiStr,
{
    if !values.is_empty() {
        params.push((field, join_api_values(values)));
    }
}

pub(crate) fn push_api_param<T>(
    params: &mut Vec<QueryParam>,
    field: &'static str,
    value: Option<&T>,
) where
    T: AsApiStr + ?Sized,
{
    if let Some(value) = value {
        params.push((field, value.as_api_str().into_owned()));
    }
}

pub(crate) fn push_display_param<T>(
    params: &mut Vec<QueryParam>,
    field: &'static str,
    value: Option<T>,
) where
    T: Display,
{
    if let Some(value) = value {
        params.push((field, value.to_string()));
    }
}

pub(crate) fn push_float_param(
    params: &mut Vec<QueryParam>,
    field: &'static str,
    value: Option<f64>,
) {
    if let Some(value) = value {
        params.push((field, format_float_param(value)));
    }
}

fn format_float_param(value: f64) -> String {
    if value.is_nan() {
        "nan".to_owned()
    } else {
        value.to_string()
    }
}