use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::marker::PhantomData;
use crate::metadata::ThriftAnnotations;
pub trait ThriftAdapter {
type StandardType;
type AdaptedType: Clone + Debug + PartialEq + Send + Sync;
type Error: Into<anyhow::Error> + Debug;
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error>;
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType;
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
_field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
Self::from_thrift(value)
}
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
_field_id: i16,
) -> Self::StandardType {
Self::to_thrift(value)
}
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
Self::from_thrift_field::<T>(value, field_id).unwrap_or_else(|e| {
panic!(
"`from_thrift_field` must not return an `Err` on field ID {} for its default value, but it did: '{:?}'",
field_id, e
);
})
}
}
pub struct LayeredThriftAdapter<Fst, Snd>
where
Fst: ThriftAdapter,
Snd: ThriftAdapter,
Fst::StandardType: Into<Snd::AdaptedType>,
Snd::AdaptedType: Into<Fst::StandardType>,
{
_inner_first: PhantomData<Fst>,
_inner_second: PhantomData<Snd>,
}
impl<Fst, Snd> ThriftAdapter for LayeredThriftAdapter<Fst, Snd>
where
Fst: ThriftAdapter,
Snd: ThriftAdapter,
Fst::StandardType: Into<Snd::AdaptedType>,
Snd::AdaptedType: Into<Fst::StandardType>,
{
type StandardType = <Snd as ThriftAdapter>::StandardType;
type AdaptedType = <Fst as ThriftAdapter>::AdaptedType;
type Error = anyhow::Error;
#[inline]
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
<Fst as ThriftAdapter>::from_thrift(
<Snd as ThriftAdapter>::from_thrift(value)
.map_err(Into::<anyhow::Error>::into)?
.into(),
)
.map_err(Into::<anyhow::Error>::into)
}
#[inline]
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
<Snd as ThriftAdapter>::to_thrift(&<Fst as ThriftAdapter>::to_thrift(value).into())
}
#[inline]
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
<Fst as ThriftAdapter>::from_thrift_field::<T>(
<Snd as ThriftAdapter>::from_thrift_field::<T>(value, field_id)
.map_err(Into::<anyhow::Error>::into)?
.into(),
field_id,
)
.map_err(Into::<anyhow::Error>::into)
}
#[inline]
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
<Snd as ThriftAdapter>::to_thrift_field::<T>(
&<Fst as ThriftAdapter>::to_thrift_field::<T>(value, field_id).into(),
field_id,
)
}
#[inline]
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
<Fst as ThriftAdapter>::from_thrift_default::<T>(
<Snd as ThriftAdapter>::from_thrift_default::<T>(value, field_id).into(),
field_id,
)
}
}
pub struct ListMapAdapter<A>
where
A: ThriftAdapter,
{
_inner_adapter: PhantomData<A>,
}
impl<A> ThriftAdapter for ListMapAdapter<A>
where
A: ThriftAdapter,
{
type StandardType = Vec<A::StandardType>;
type AdaptedType = Vec<A::AdaptedType>;
type Error = A::Error;
#[inline]
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|elem| A::from_thrift(elem))
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value.iter().map(|elem| A::to_thrift(elem)).collect()
}
#[inline]
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|elem| A::from_thrift_field::<T>(elem, field_id))
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
value
.iter()
.map(|elem| A::to_thrift_field::<T>(elem, field_id))
.collect()
}
#[inline]
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
value
.into_iter()
.map(|elem| A::from_thrift_default::<T>(elem, field_id))
.collect()
}
}
pub struct SetMapAdapter<A>
where
A: ThriftAdapter,
A::StandardType: Ord + PartialEq,
A::AdaptedType: Ord + PartialEq,
{
_inner_adapter: PhantomData<A>,
}
impl<A> ThriftAdapter for SetMapAdapter<A>
where
A: ThriftAdapter,
A::StandardType: Ord + PartialEq,
A::AdaptedType: Ord + PartialEq,
{
type StandardType = BTreeSet<A::StandardType>;
type AdaptedType = BTreeSet<A::AdaptedType>;
type Error = A::Error;
#[inline]
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|elem| A::from_thrift(elem))
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value.iter().map(|elem| A::to_thrift(elem)).collect()
}
#[inline]
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|elem| A::from_thrift_field::<T>(elem, field_id))
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
value
.iter()
.map(|elem| A::to_thrift_field::<T>(elem, field_id))
.collect()
}
#[inline]
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
value
.into_iter()
.map(|elem| A::from_thrift_default::<T>(elem, field_id))
.collect()
}
}
pub struct MapMapAdapter<KA, KV>
where
KA: ThriftAdapter,
KV: ThriftAdapter,
KA::StandardType: Ord + PartialEq,
KA::AdaptedType: Ord + PartialEq,
{
_inner_key_adapter: PhantomData<KA>,
_inner_val_adapter: PhantomData<KV>,
}
impl<KA, KV> ThriftAdapter for MapMapAdapter<KA, KV>
where
KA: ThriftAdapter,
KV: ThriftAdapter,
KA::StandardType: Ord + PartialEq,
KA::AdaptedType: Ord + PartialEq,
{
type StandardType = BTreeMap<KA::StandardType, KV::StandardType>;
type AdaptedType = BTreeMap<KA::AdaptedType, KV::AdaptedType>;
type Error = anyhow::Error;
#[inline]
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|(key, val)| {
Ok((
KA::from_thrift(key).map_err(Into::<anyhow::Error>::into)?,
KV::from_thrift(val).map_err(Into::<anyhow::Error>::into)?,
))
})
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value
.iter()
.map(|(key, val)| (KA::to_thrift(key), KV::to_thrift(val)))
.collect::<Self::StandardType>()
}
#[inline]
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
value
.into_iter()
.map(|(key, val)| {
Ok((
KA::from_thrift_field::<T>(key, field_id)
.map_err(Into::<anyhow::Error>::into)?,
KV::from_thrift_field::<T>(val, field_id)
.map_err(Into::<anyhow::Error>::into)?,
))
})
.collect::<Result<Self::AdaptedType, Self::Error>>()
}
#[inline]
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
value
.iter()
.map(|(key, val)| {
(
KA::to_thrift_field::<T>(key, field_id),
KV::to_thrift_field::<T>(val, field_id),
)
})
.collect::<Self::StandardType>()
}
#[inline]
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
value
.into_iter()
.map(|(key, val)| {
(
KA::from_thrift_default::<T>(key, field_id),
KV::from_thrift_default::<T>(val, field_id),
)
})
.collect::<Self::AdaptedType>()
}
}
pub struct IdentityAdapter<T>
where
T: Clone + Debug + Send + Sync + PartialEq,
{
_inner: PhantomData<T>,
}
impl<T> ThriftAdapter for IdentityAdapter<T>
where
T: Clone + Debug + Send + Sync + PartialEq,
{
type StandardType = T;
type AdaptedType = T;
type Error = std::convert::Infallible;
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
Ok(value)
}
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value.clone()
}
}
pub trait NewTypeAdapter {
type StandardType;
type AdaptedType;
}
impl<Adapter, StandardType, AdaptedType> ThriftAdapter for Adapter
where
Adapter: NewTypeAdapter<StandardType = StandardType, AdaptedType = AdaptedType>,
AdaptedType: From<StandardType> + Into<StandardType> + Clone + Debug + Send + Sync + PartialEq,
{
type StandardType = <Self as NewTypeAdapter>::StandardType;
type AdaptedType = <Self as NewTypeAdapter>::AdaptedType;
type Error = <Self::AdaptedType as TryFrom<Self::StandardType>>::Error;
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value.clone().into()
}
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
Self::AdaptedType::try_from(value)
}
}
#[cfg(test)]
mod tests {
use std::any::TypeId;
use super::*;
struct DummyParentStruct {}
impl ThriftAnnotations for DummyParentStruct {}
struct BoolToStringAdapter {}
impl ThriftAdapter for BoolToStringAdapter {
type StandardType = bool;
type AdaptedType = String;
type Error = anyhow::Error;
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
Ok(value.to_string())
}
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
value == "true"
}
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift(value)
}
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::to_thrift(value)
}
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift_field::<T>(value, field_id).unwrap()
}
}
struct I64ToBoolAdapter {}
impl ThriftAdapter for I64ToBoolAdapter {
type StandardType = i64;
type AdaptedType = bool;
type Error = anyhow::Error;
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
match value {
0 => Ok(false),
1 => Ok(true),
other => anyhow::bail!("invalid num {}", other),
}
}
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
if *value { 1 } else { 0 }
}
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift(value)
}
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::to_thrift(value)
}
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift_field::<T>(value, field_id).unwrap()
}
}
struct I8ToI64Adapter {}
impl ThriftAdapter for I8ToI64Adapter {
type StandardType = i8;
type AdaptedType = i64;
type Error = anyhow::Error;
fn from_thrift(value: Self::StandardType) -> Result<Self::AdaptedType, Self::Error> {
Ok(value.into())
}
fn to_thrift(value: &Self::AdaptedType) -> Self::StandardType {
(*value).try_into().unwrap()
}
fn from_thrift_field<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Result<Self::AdaptedType, Self::Error> {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift(value)
}
fn to_thrift_field<T: ThriftAnnotations>(
value: &Self::AdaptedType,
field_id: i16,
) -> Self::StandardType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::to_thrift(value)
}
fn from_thrift_default<T: ThriftAnnotations>(
value: Self::StandardType,
field_id: i16,
) -> Self::AdaptedType {
assert_eq!(field_id, 42);
assert_eq!(TypeId::of::<DummyParentStruct>(), TypeId::of::<T>());
Self::from_thrift_field::<T>(value, field_id).unwrap()
}
}
type TestLayeredAdapter = LayeredThriftAdapter<
BoolToStringAdapter,
LayeredThriftAdapter<I64ToBoolAdapter, I8ToI64Adapter>,
>;
#[test]
fn test_from_thrift() {
assert_eq!(TestLayeredAdapter::from_thrift(0_i8).unwrap(), "false");
assert_eq!(TestLayeredAdapter::from_thrift(1_i8).unwrap(), "true");
}
#[test]
fn test_from_thrift_error() {
let res = TestLayeredAdapter::from_thrift(3_i8);
assert!(res.is_err());
assert_eq!(res.unwrap_err().to_string(), "invalid num 3");
}
#[test]
fn test_to_thrift() {
assert_eq!(TestLayeredAdapter::to_thrift(&"false".to_string()), 0_i8);
assert_eq!(TestLayeredAdapter::to_thrift(&"true".to_string()), 1_i8);
}
#[test]
fn test_thrift_field() {
assert_eq!(
TestLayeredAdapter::from_thrift_field::<DummyParentStruct>(0_i8, 42).unwrap(),
"false"
);
assert_eq!(
TestLayeredAdapter::from_thrift_default::<DummyParentStruct>(0_i8, 42),
"false"
);
assert_eq!(
TestLayeredAdapter::to_thrift_field::<DummyParentStruct>(&"false".to_string(), 42),
0_i8
);
}
}