use std::time::Duration;
use serde::{de::Unexpected, Deserialize, Deserializer, Serialize};
use crate::{event::cmap::*, options::ServerAddress};
impl Serialize for CmapEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Self::PoolCreated(event) => event.serialize(serializer),
Self::PoolClosed(event) => event.serialize(serializer),
Self::PoolReady(event) => event.serialize(serializer),
Self::ConnectionCreated(event) => event.serialize(serializer),
Self::ConnectionReady(event) => event.serialize(serializer),
Self::ConnectionClosed(event) => event.serialize(serializer),
Self::ConnectionCheckoutStarted(event) => event.serialize(serializer),
Self::ConnectionCheckoutFailed(event) => event.serialize(serializer),
Self::ConnectionCheckedOut(event) => event.serialize(serializer),
Self::PoolCleared(event) => event.serialize(serializer),
Self::ConnectionCheckedIn(event) => event.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for CmapEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(tag = "type")]
#[allow(clippy::enum_variant_names)]
enum EventHelper {
#[serde(deserialize_with = "self::deserialize_pool_created")]
ConnectionPoolCreated(PoolCreatedEvent),
ConnectionPoolClosed(PoolClosedEvent),
ConnectionPoolReady(PoolReadyEvent),
ConnectionCreated(ConnectionCreatedEvent),
ConnectionReady(ConnectionReadyEvent),
ConnectionClosed(ConnectionClosedEvent),
ConnectionCheckOutStarted(ConnectionCheckoutStartedEvent),
#[serde(deserialize_with = "self::deserialize_checkout_failed")]
ConnectionCheckOutFailed(ConnectionCheckoutFailedEvent),
ConnectionCheckedOut(ConnectionCheckedOutEvent),
ConnectionPoolCleared(PoolClearedEvent),
ConnectionCheckedIn(ConnectionCheckedInEvent),
}
let helper = EventHelper::deserialize(deserializer)?;
let event = match helper {
EventHelper::ConnectionPoolCreated(e) => CmapEvent::PoolCreated(e),
EventHelper::ConnectionPoolClosed(e) => CmapEvent::PoolClosed(e),
EventHelper::ConnectionPoolReady(e) => CmapEvent::PoolReady(e),
EventHelper::ConnectionCreated(e) => CmapEvent::ConnectionCreated(e),
EventHelper::ConnectionReady(e) => CmapEvent::ConnectionReady(e),
EventHelper::ConnectionClosed(e) => CmapEvent::ConnectionClosed(e),
EventHelper::ConnectionCheckOutStarted(e) => CmapEvent::ConnectionCheckoutStarted(e),
EventHelper::ConnectionCheckOutFailed(e) => CmapEvent::ConnectionCheckoutFailed(e),
EventHelper::ConnectionCheckedOut(e) => CmapEvent::ConnectionCheckedOut(e),
EventHelper::ConnectionPoolCleared(e) => CmapEvent::PoolCleared(e),
EventHelper::ConnectionCheckedIn(e) => CmapEvent::ConnectionCheckedIn(e),
};
Ok(event)
}
}
impl CmapEvent {
pub(crate) fn name(&self) -> &'static str {
match self {
CmapEvent::PoolCreated(_) => "ConnectionPoolCreated",
CmapEvent::PoolReady(_) => "ConnectionPoolReady",
CmapEvent::PoolClosed(_) => "ConnectionPoolClosed",
CmapEvent::ConnectionCreated(_) => "ConnectionCreated",
CmapEvent::ConnectionReady(_) => "ConnectionReady",
CmapEvent::ConnectionClosed(_) => "ConnectionClosed",
CmapEvent::ConnectionCheckoutStarted(_) => "ConnectionCheckOutStarted",
CmapEvent::ConnectionCheckoutFailed(_) => "ConnectionCheckOutFailed",
CmapEvent::ConnectionCheckedOut(_) => "ConnectionCheckedOut",
CmapEvent::PoolCleared(_) => "ConnectionPoolCleared",
CmapEvent::ConnectionCheckedIn(_) => "ConnectionCheckedIn",
}
}
}
#[derive(Debug, Deserialize)]
struct PoolCreatedEventHelper {
#[serde(default)]
pub options: Option<PoolOptionsHelper>,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum PoolOptionsHelper {
Number(u64),
Options(ConnectionPoolOptions),
}
fn deserialize_pool_created<'de, D>(deserializer: D) -> Result<PoolCreatedEvent, D::Error>
where
D: Deserializer<'de>,
{
let helper = PoolCreatedEventHelper::deserialize(deserializer)?;
let options = match helper.options {
Some(PoolOptionsHelper::Options(opts)) => Some(opts),
Some(PoolOptionsHelper::Number(42)) | None => None,
Some(PoolOptionsHelper::Number(other)) => {
return Err(serde::de::Error::invalid_value(
Unexpected::Unsigned(other),
&"42",
));
}
};
Ok(PoolCreatedEvent {
address: ServerAddress::Tcp {
host: Default::default(),
port: None,
},
options,
})
}
#[derive(Debug, Deserialize)]
struct ConnectionCheckoutFailedHelper {
reason: Option<CheckoutFailedReasonHelper>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
enum CheckoutFailedReasonHelper {
Timeout,
ConnectionError,
PoolClosed,
}
fn deserialize_checkout_failed<'de, D>(
deserializer: D,
) -> Result<ConnectionCheckoutFailedEvent, D::Error>
where
D: Deserializer<'de>,
{
let helper = ConnectionCheckoutFailedHelper::deserialize(deserializer)?;
let reason = match helper.reason {
Some(CheckoutFailedReasonHelper::ConnectionError) => {
ConnectionCheckoutFailedReason::ConnectionError
}
Some(CheckoutFailedReasonHelper::Timeout) => ConnectionCheckoutFailedReason::Timeout,
Some(CheckoutFailedReasonHelper::PoolClosed) | None => {
ConnectionCheckoutFailedReason::Unset
}
};
Ok(ConnectionCheckoutFailedEvent {
address: ServerAddress::Tcp {
host: Default::default(),
port: None,
},
reason,
#[cfg(feature = "tracing-unstable")]
error: None,
duration: Duration::ZERO,
})
}