use crate::{ClientError, Error, resp::ArgCounter};
use serde::{
Deserializer, Serialize, Serializer,
de::{self, DeserializeOwned, DeserializeSeed, Visitor},
};
use std::{fmt, marker::PhantomData};
pub fn deserialize_vec_of_pairs<'de, D, T1, T2>(
deserializer: D,
) -> std::result::Result<Vec<(T1, T2)>, D::Error>
where
D: Deserializer<'de>,
T1: DeserializeOwned,
T2: DeserializeOwned,
{
struct VecOfPairsVisitor<T1, T2>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
{
phantom: PhantomData<(T1, T2)>,
}
impl<'de, T1, T2> Visitor<'de> for VecOfPairsVisitor<T1, T2>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
{
type Value = Vec<(T1, T2)>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Vec<(T1, T2)>")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut v = if let Some(size) = seq.size_hint() {
Vec::with_capacity(size / 2)
} else {
Vec::new()
};
while let Some(first) = seq.next_element()? {
let Some(second) = seq.next_element()? else {
return Err(de::Error::custom("invalid length"));
};
v.push((first, second));
}
Ok(v)
}
}
deserializer.deserialize_seq(VecOfPairsVisitor {
phantom: PhantomData,
})
}
pub fn deserialize_vec_of_triplets<'de, D, T1, T2, T3>(
deserializer: D,
) -> std::result::Result<Vec<(T1, T2, T3)>, D::Error>
where
D: Deserializer<'de>,
T1: DeserializeOwned,
T2: DeserializeOwned,
T3: DeserializeOwned,
{
struct VecOfTripletVisitor<T1, T2, T3>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
T3: DeserializeOwned,
{
phantom: PhantomData<(T1, T2, T3)>,
}
impl<'de, T1, T2, T3> Visitor<'de> for VecOfTripletVisitor<T1, T2, T3>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
T3: DeserializeOwned,
{
type Value = Vec<(T1, T2, T3)>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Vec<(T1, T2, T3)>")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut v = if let Some(size) = seq.size_hint() {
Vec::with_capacity(size / 3)
} else {
Vec::new()
};
while let Some(first) = seq.next_element()? {
let Some(second) = seq.next_element()? else {
return Err(de::Error::custom("invalid length"));
};
let Some(third) = seq.next_element()? else {
return Err(de::Error::custom("invalid length"));
};
v.push((first, second, third));
}
Ok(v)
}
}
deserializer.deserialize_seq(VecOfTripletVisitor {
phantom: PhantomData,
})
}
pub fn deserialize_byte_buf<'de, D>(deserializer: D) -> std::result::Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
struct ByteBufVisitor;
impl Visitor<'_> for ByteBufVisitor {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Vec<u8>")
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(v)
}
}
deserializer.deserialize_byte_buf(ByteBufVisitor)
}
pub fn serialize_byte_buf<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(bytes)
}
pub fn serialize_byte_buf_option<S>(bytes: &Option<&[u8]>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(bytes) = bytes {
serializer.serialize_bytes(bytes)
} else {
serializer.serialize_none()
}
}
pub(crate) struct ByteBufSeed;
impl<'de> DeserializeSeed<'de> for ByteBufSeed {
type Value = Vec<u8>;
fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserialize_byte_buf(deserializer)
}
}
pub fn deserialize_bytes<'de, D>(deserializer: D) -> std::result::Result<&'de [u8], D::Error>
where
D: Deserializer<'de>,
{
struct ByteBufVisitor;
impl<'de> Visitor<'de> for ByteBufVisitor {
type Value = &'de [u8];
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("&'de [u8]")
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(v)
}
}
deserializer.deserialize_bytes(ByteBufVisitor)
}
#[derive(Default)]
pub(crate) struct VecOfPairsSeed<T1, T2>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
{
phatom: PhantomData<(T1, T2)>,
}
impl<T1, T2> VecOfPairsSeed<T1, T2>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
{
#[allow(dead_code)]
pub(crate) fn new() -> Self {
Self {
phatom: PhantomData,
}
}
}
impl<'de, T1, T2> DeserializeSeed<'de> for VecOfPairsSeed<T1, T2>
where
T1: DeserializeOwned,
T2: DeserializeOwned,
{
type Value = Vec<(T1, T2)>;
#[inline]
fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserialize_vec_of_pairs(deserializer)
}
}
pub(crate) fn is_field_value_array(
len: usize,
first_key: Option<&[u8]>,
fields: &'static [&'static str],
) -> bool {
len.is_multiple_of(2)
&& first_key.is_some_and(|key| fields.iter().any(|field| field.as_bytes() == key))
}
#[inline]
pub(crate) fn double_to_int<T>(d: f64) -> Result<T, Error>
where
T: TryFrom<i128>,
{
const I128_MIN: f64 = -170_141_183_460_469_231_731_687_303_715_884_105_728.0;
const I128_MAX_EXCLUSIVE: f64 = 170_141_183_460_469_231_731_687_303_715_884_105_728.0;
if !d.is_finite() || d.fract() != 0. || !(I128_MIN..I128_MAX_EXCLUSIVE).contains(&d) {
return Err(Error::Client(ClientError::CannotParseInteger));
}
#[expect(
clippy::cast_possible_truncation,
reason = "the guard above leaves only finite integral doubles inside i128's range, where the cast is exact"
)]
let integral = d as i128;
T::try_from(integral).map_err(|_| Error::Client(ClientError::CannotParseInteger))
}
pub(crate) fn serialize_flag<S: serde::Serializer>(
_: &bool,
serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
serializer.serialize_unit()
}
pub(crate) fn serialize_slice_with_arg_count<S, T>(
slice: &[T],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Serialize,
{
(count_args::<_, S::Error>(&slice)?, slice).serialize(serializer)
}
pub(crate) fn count_args<T, E>(value: &T) -> Result<usize, E>
where
T: Serialize + ?Sized,
E: serde::ser::Error,
{
let mut counter = ArgCounter::default();
value.serialize(&mut counter).map_err(E::custom)?;
Ok(counter.count)
}