use core::any::type_name;
use core::fmt::Debug;
use core::fmt::Formatter;
use core::fmt::Result as FmtResult;
use std::any::Any;
use std::any::TypeId;
use std::error::Error;
use crate::ValueCodecExecutionError;
use crate::ValueDecoder;
use crate::ValueEncoder;
type EncodeFn = fn(&dyn Any) -> Result<Vec<u8>, ValueCodecExecutionError>;
type DecodeFn = fn(&[u8]) -> Result<Box<dyn Any>, ValueCodecExecutionError>;
#[derive(Clone, Copy)]
pub struct ValueBytesCodecDescriptor {
codec_type_id: fn() -> TypeId,
codec_type_name: fn() -> &'static str,
value_type_id: fn() -> TypeId,
value_type_name: fn() -> &'static str,
encode: EncodeFn,
decode: DecodeFn,
}
impl ValueBytesCodecDescriptor {
#[must_use]
#[inline]
pub const fn of<C, V>() -> Self
where
C: Default + ValueEncoder<V, Output = Vec<u8>> + ValueDecoder<[u8], Output = V> + 'static,
<C as ValueEncoder<V>>::Error: Error + Send + Sync + 'static,
<C as ValueDecoder<[u8]>>::Error: Error + Send + Sync + 'static,
V: 'static,
{
Self {
codec_type_id: TypeId::of::<C>,
codec_type_name: type_name::<C>,
value_type_id: TypeId::of::<V>,
value_type_name: type_name::<V>,
encode: encode::<C, V>,
decode: decode::<C, V>,
}
}
#[must_use]
#[inline]
pub fn codec_type_id(&self) -> TypeId {
(self.codec_type_id)()
}
#[must_use]
#[inline]
pub fn codec_type_name(&self) -> &'static str {
(self.codec_type_name)()
}
#[must_use]
#[inline]
pub fn value_type_id(&self) -> TypeId {
(self.value_type_id)()
}
#[must_use]
#[inline]
pub fn value_type_name(&self) -> &'static str {
(self.value_type_name)()
}
#[inline]
pub fn encode(&self, value: &dyn Any) -> Result<Vec<u8>, ValueCodecExecutionError> {
(self.encode)(value)
}
#[inline]
pub fn decode(&self, input: &[u8]) -> Result<Box<dyn Any>, ValueCodecExecutionError> {
(self.decode)(input)
}
}
impl Debug for ValueBytesCodecDescriptor {
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
formatter
.debug_struct("ValueBytesCodecDescriptor")
.field("codec_type_name", &self.codec_type_name())
.field("value_type_name", &self.value_type_name())
.finish_non_exhaustive()
}
}
fn encode<C, V>(value: &dyn Any) -> Result<Vec<u8>, ValueCodecExecutionError>
where
C: Default + ValueEncoder<V, Output = Vec<u8>> + ValueDecoder<[u8], Output = V> + 'static,
<C as ValueEncoder<V>>::Error: Error + Send + Sync + 'static,
<C as ValueDecoder<[u8]>>::Error: Error + Send + Sync + 'static,
V: 'static,
{
let value = value
.downcast_ref::<V>()
.ok_or_else(|| ValueCodecExecutionError::TypeMismatch {
expected_type: type_name::<V>(),
actual_type: value.type_id(),
})?;
C::default()
.encode(value)
.map_err(|source| ValueCodecExecutionError::EncodeFailed {
codec_type: type_name::<C>(),
source: Box::new(source),
})
}
fn decode<C, V>(input: &[u8]) -> Result<Box<dyn Any>, ValueCodecExecutionError>
where
C: Default + ValueEncoder<V, Output = Vec<u8>> + ValueDecoder<[u8], Output = V> + 'static,
<C as ValueEncoder<V>>::Error: Error + Send + Sync + 'static,
<C as ValueDecoder<[u8]>>::Error: Error + Send + Sync + 'static,
V: 'static,
{
C::default()
.decode(input)
.map(|value| Box::new(value) as Box<dyn Any>)
.map_err(|source| ValueCodecExecutionError::DecodeFailed {
codec_type: type_name::<C>(),
source: Box::new(source),
})
}