~goorzhel/sota-slack-spotter

b52cec66b2f63aa4cd638dff3c0aeaccf0de241b — Antonio Gurgel 2 months ago cf0e603
Use serde_with to resolve ""/None discrepancy
3 files changed, 9 insertions(+), 14 deletions(-)

M src/sota/alert.rs
M src/sota/mod.rs
M src/sota/spot.rs
M src/sota/alert.rs => src/sota/alert.rs +3 -0
@@ 8,6 8,7 @@ use std::{
use anyhow::{anyhow, Result};
use reqwest::blocking::get;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use time::{format_description::parse as parse_format, OffsetDateTime};

use crate::callsign::Callsign;


@@ 30,6 31,7 @@ pub fn all_alerts() -> Result<Vec<Alert>> {
/// An alert is something like a future spot: it states that the named operator
/// plans to activate a summit at the given time.
#[derive(Debug, Clone, Deserialize, Serialize, Eq)]
#[serde_as]
#[serde(rename_all = "camelCase")]
pub struct Alert {
    pub activating_callsign: Callsign,


@@ 44,6 46,7 @@ pub struct Alert {
    /// The time for which the activation is planned.
    #[serde(with = "time::serde::rfc3339")]
    pub date_activated: OffsetDateTime,
    #[serde_as(as = "NoneAsEmptyString")]
    pub comments: Option<String>,
}


M src/sota/mod.rs => src/sota/mod.rs +3 -14
@@ 3,7 3,8 @@ pub mod spot;

use std::{fmt::Display, hash::Hash, str::FromStr};

use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{de::DeserializeOwned, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};

use crate::callsign::{Callsign, Callsigns};



@@ 21,7 22,7 @@ pub trait SOTAItem: Hash + Eq + DeserializeOwned + Serialize {
}

#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr)]
pub enum Mode {
    AM,
    CW,


@@ 32,18 33,6 @@ pub enum Mode {
    Other,
}

// https://github.com/serde-rs/serde/issues/908#issuecomment-298027413
// Importing `serde_with` would mean another twenty crates.
impl<'de> Deserialize<'de> for Mode {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        FromStr::from_str(&s).map_err(serde::de::Error::custom)
    }
}

impl FromStr for Mode {
    type Err = anyhow::Error;


M src/sota/spot.rs => src/sota/spot.rs +3 -0
@@ 9,6 9,7 @@ use std::{
use anyhow::{anyhow, Result};
use reqwest::blocking::get;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use time::{format_description::parse as parse_format, OffsetDateTime};

use crate::{


@@ 28,6 29,7 @@ pub fn all_spots(hours: u8) -> Result<Vec<Spot>> {

/// A SOTA spot.
#[derive(Debug, Clone, Deserialize, Serialize, Eq)]
#[serde_as]
#[serde(rename_all = "camelCase")]
pub struct Spot {
    pub activator_callsign: Callsign,


@@ 40,6 42,7 @@ pub struct Spot {
    #[serde(with = "time::serde::rfc3339")]
    pub time_stamp: OffsetDateTime,
    pub callsign: Callsign,
    #[serde_as(as = "NoneAsEmptyString")]
    pub comments: Option<String>,
}