diff --git a/src/address/envelope.rs b/src/address/envelope.rs index 65fb090..3a4aae1 100644 --- a/src/address/envelope.rs +++ b/src/address/envelope.rs @@ -14,11 +14,71 @@ pub struct Envelope { /// The envelope recipient's addresses /// /// This can not be empty. + #[cfg_attr( + feature = "serde", + serde(deserialize_with = "serde_forward_path::deserialize") + )] forward_path: Vec
, /// The envelope sender address reverse_path: Option
, } +/// just like the default implementation to deserialize `Vec
` but it +/// forbids **de**serializing empty lists +#[cfg(feature = "serde")] +mod serde_forward_path { + use super::Address; + /// dummy type required for serde + /// see example: https://serde.rs/deserialize-map.html + struct CustomVisitor; + impl<'de> serde::de::Visitor<'de> for CustomVisitor { + type Value = Vec
; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a non-empty list of recipient addresses") + } + + fn visit_seq(self, mut access: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let mut seq: Vec
= Vec::with_capacity(access.size_hint().unwrap_or(0)); + while let Some(key) = access.next_element()? { + seq.push(key); + } + if seq.is_empty() { + Err(serde::de::Error::invalid_length(seq.len(), &self)) + } else { + Ok(seq) + } + } + } + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_seq(CustomVisitor {}) + } + + #[cfg(test)] + mod tests { + #[test] + fn deserializing_empty_recipient_list_returns_error() { + assert!( + serde_json::from_str::(r#"{"forward_path": []}"#) + .is_err() + ); + } + #[test] + fn deserializing_non_empty_recipient_list_is_ok() { + serde_json::from_str::( + r#"{ "forward_path": [ {"user":"foo", "domain":"example.com"} ] }"#, + ) + .unwrap(); + } + } +} + impl Envelope { /// Creates a new envelope, which may fail if `to` is empty. ///