openleadr-wire 0.2.6

Encode and decode OpenADR 3.1 messages that go over the wire
Documentation
use http::StatusCode;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct ProblemUri(String);

impl Default for ProblemUri {
    fn default() -> Self {
        Self("about:blank".to_string())
    }
}

/// Reusable error response. From <https://opensource.zalando.com/problem/schema.yaml>.
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct Problem {
    /// An absolute URI that identifies the problem type.
    /// When dereferenced, it SHOULD provide human-readable documentation for the problem type
    /// (e.g., using HTML).
    #[serde(default)]
    pub r#type: ProblemUri,
    /// A short, summary of the problem type.
    /// Written in english and readable for engineers
    /// (usually not suited for non-technical stakeholders and not localized);
    /// example: Service Unavailable.
    pub title: Option<String>,
    /// The HTTP status code generated by the origin server for this occurrence of the problem.
    #[serde(with = "status_code_serialization")]
    pub status: StatusCode,
    /// A human-readable explanation specific to this occurrence of the problem.
    pub detail: Option<String>,
    /// An absolute URI that identifies the specific occurrence of the problem.
    /// It may or may not yield further information if dereferenced.
    pub instance: Option<String>,
}

mod status_code_serialization {
    use super::*;

    use serde::{Deserializer, Serializer, de::Unexpected};

    pub fn serialize<S>(code: &StatusCode, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u16(code.as_u16())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<StatusCode, D::Error>
    where
        D: Deserializer<'de>,
    {
        u16::deserialize(deserializer).and_then(|code| {
            StatusCode::from_u16(code).map_err(|_| {
                serde::de::Error::invalid_value(
                    Unexpected::Unsigned(code as u64),
                    &"Valid http status code",
                )
            })
        })
    }
}