use core::fmt::Debug;
use musli::de::PackDecoder;
use musli::mode::{DefaultMode, Mode};
use musli::Context;
use musli::{Decode, Decoder, Encode};
use crate::tag::Tag;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Typed<T> {
tag: Tag,
value: T,
}
impl<T> Typed<T> {
pub const fn new(tag: Tag, value: T) -> Self {
Self { tag, value }
}
}
impl<'de, M, T> Decode<'de, M> for Typed<T>
where
M: Mode,
T: Decode<'de, M>,
{
fn decode<C, D>(cx: &mut C, decoder: D) -> Result<Self, C::Error>
where
C: Context<Input = D::Error>,
D: Decoder<'de>,
{
let mut unpack = decoder.decode_pack(cx)?;
let tag = unpack
.next(cx)
.and_then(|v| <Tag as Decode<M>>::decode(cx, v))?;
let value = unpack
.next(cx)
.and_then(|v| <T as Decode<M>>::decode(cx, v))?;
unpack.end(cx)?;
Ok(Self { tag, value })
}
}
#[macro_export]
macro_rules! rt {
($enum:ident :: $variant:ident $($body:tt)?) => {
$crate::rt!($enum, $enum :: $variant $($body)*)
};
($struct:ident $($body:tt)?) => {
$crate::rt!($struct, $struct $($body)*)
};
($ty:ty, $expr:expr) => {{
let value: $ty = $expr;
let out = $crate::to_vec(&value).expect(concat!("wire: ", stringify!($ty), ": failed to encode"));
let decoded: $ty = $crate::from_slice(out.as_slice()).expect(concat!("wire: ", stringify!($ty), ": failed to decode"));
assert_eq!(decoded, $expr, concat!("wire: ", stringify!($ty), ": roundtrip does not match"));
decoded
}};
}
#[inline(never)]
pub fn transcode<T, O>(value: T) -> O
where
T: Debug + PartialEq + Encode<DefaultMode>,
O: for<'de> Decode<'de, DefaultMode>,
{
let out = crate::to_vec(&value).expect("failed to encode");
let mut buf = out.as_slice();
let value: O = crate::decode(&mut buf).expect("failed to decode");
assert!(buf.is_empty());
value
}