use std::marker::PhantomData;
use serde::{de::Visitor, Deserialize, Deserializer};
use crate::soap::Header;
use crate::OperationResponse;
use super::Fault;
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub(super) struct DeserializeEnvelope<T>
where
T: OperationResponse,
{
pub header: Option<SoapHeaders>,
#[serde(deserialize_with = "deserialize_body")]
pub body: EnvelopeContent<T>,
}
#[derive(Deserialize)]
pub struct SoapHeaders {
#[serde(rename = "$value", default)]
pub inner: Vec<Header>,
}
#[derive(Deserialize)]
pub enum EnvelopeContent<T> {
Fault(Fault),
Body(T),
}
fn deserialize_body<'de, D, T>(body: D) -> Result<EnvelopeContent<T>, D::Error>
where
D: Deserializer<'de>,
T: OperationResponse,
{
body.deserialize_map(BodyVisitor::<T>(PhantomData))
}
struct BodyVisitor<T>(PhantomData<T>);
fn consume_final_none<'de, A: serde::de::MapAccess<'de>>(mut map: A) -> Result<(), A::Error> {
match map.next_key::<String>()? {
Some(name) => {
Err(serde::de::Error::custom(format_args!(
"unexpected element `{name}`"
)))
}
None => Ok(()),
}
}
impl<'de, T> Visitor<'de> for BodyVisitor<T>
where
T: OperationResponse,
{
type Value = EnvelopeContent<T>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("EWS operation response body")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
loop {
match map.next_key::<String>()?.as_deref() {
Some("Fault") => {
let value: Fault = map.next_value()?;
consume_final_none(map)?;
return Ok(EnvelopeContent::Fault(value));
}
Some(name) if name.starts_with('@') => {
map.next_value::<()>()?;
continue;
}
Some(name) => {
let expected = T::NAME;
if name != expected {
return Err(serde::de::Error::custom(format_args!(
"unknown element `{name}`, expected {expected}"
)));
}
let value: T = map.next_value()?;
consume_final_none(map)?;
return Ok(EnvelopeContent::Body(value));
}
None => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Map,
&self,
))
}
}
}
}
}