use core::any::{TypeId, type_name};
pub use cu29_value_types::{QuantityMetadata, TimeStorageUnit, ValueMetadata};
pub trait ValueDecode: 'static + Sized {
const DECODE: &'static ValueDecodeSpec;
const METADATA: &'static [ValueMetadata] = &[];
#[doc(hidden)]
const __DECODE_REF: ValueDecodeRef = ValueDecodeRef {
describe: describe::<Self>,
};
}
#[derive(Clone, Copy, Debug)]
pub struct ValueDecodeRef {
pub describe: fn() -> ValueDecodeType,
}
impl ValueDecodeRef {
pub const fn of<T: ValueDecode>() -> Self {
Self {
describe: describe::<T>,
}
}
}
fn describe<T: ValueDecode>() -> ValueDecodeType {
ValueDecodeType {
type_id: TypeId::of::<T>(),
type_name: type_name::<T>(),
spec: T::DECODE,
metadata: T::METADATA,
}
}
#[derive(Clone, Copy, Debug)]
pub struct ValueDecodeType {
pub type_id: TypeId,
pub type_name: &'static str,
pub spec: &'static ValueDecodeSpec,
pub metadata: &'static [ValueMetadata],
}
pub use cu29_value_types::Scalar;
#[derive(Clone, Copy, Debug)]
pub enum FieldSelector {
Named(&'static str),
Index {
index: usize,
declared_fields: usize,
},
}
#[derive(Clone, Copy, Debug)]
pub struct ValueDecodeField {
pub selector: FieldSelector,
pub declaration_index: usize,
pub value: ValueDecodeRef,
}
pub use cu29_value_types::RecordShape;
#[derive(Clone, Copy, Debug)]
pub struct ValueDecodeVariant {
pub tag: u32,
pub name: &'static str,
pub shape: RecordShape,
pub fields: &'static [ValueDecodeField],
}
#[derive(Clone, Copy, Debug)]
pub enum ValueDecodeSpec {
Unit,
Scalar(Scalar),
String,
Bytes,
Record {
shape: RecordShape,
fields: &'static [ValueDecodeField],
},
Array {
element: ValueDecodeRef,
len: usize,
},
Sequence {
element: ValueDecodeRef,
count: Scalar,
capacity: Option<usize>,
},
Map {
key: ValueDecodeRef,
value: ValueDecodeRef,
},
Option(ValueDecodeRef),
Delegate(ValueDecodeRef),
Enum {
tag: Scalar,
variants: &'static [ValueDecodeVariant],
},
}
macro_rules! scalars {
($($ty:ty => $scalar:ident),* $(,)?) => {$(
impl ValueDecode for $ty { const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Scalar(Scalar::$scalar); }
)*};
}
scalars!(bool=>Bool, u8=>U8, u16=>U16, u32=>U32, u64=>U64, u128=>U128,
i8=>I8, i16=>I16, i32=>I32, i64=>I64, i128=>I128, f32=>F32, f64=>F64, char=>Char,
usize=>U64, isize=>I64);
impl ValueDecode for () {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Unit;
}
impl<T: 'static> ValueDecode for core::marker::PhantomData<T> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Unit;
}
impl<T: ValueDecode, const N: usize> ValueDecode for [T; N] {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Array {
element: ValueDecodeRef::of::<T>(),
len: N,
};
}
impl<T: ValueDecode> ValueDecode for Option<T> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Option(ValueDecodeRef::of::<T>());
}
impl<T: ValueDecode> ValueDecode for &'static T {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Delegate(ValueDecodeRef::of::<T>());
}
impl ValueDecode for &'static str {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::String;
}
impl<T: ValueDecode> ValueDecode for &'static [T] {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Sequence {
element: ValueDecodeRef::of::<T>(),
count: Scalar::U64,
capacity: None,
};
}
#[cfg(feature = "alloc")]
mod allocated {
use super::*;
use alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet, VecDeque},
rc::Rc,
string::String,
sync::Arc,
vec::Vec,
};
impl ValueDecode for String {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::String;
}
macro_rules! sequence { ($($container:ident),*) => {$(
impl<T: ValueDecode> ValueDecode for $container<T> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Sequence { element: ValueDecodeRef::of::<T>(), count: Scalar::U64, capacity: None };
}
)*}; }
sequence!(Vec, VecDeque, BTreeSet);
impl<K: ValueDecode, V: ValueDecode> ValueDecode for BTreeMap<K, V> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Map {
key: ValueDecodeRef::of::<K>(),
value: ValueDecodeRef::of::<V>(),
};
}
macro_rules! delegate { ($($container:ident),*) => {$(
impl<T: ValueDecode> ValueDecode for $container<T> { const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Delegate(ValueDecodeRef::of::<T>()); }
)*}; }
delegate!(Box, Rc, Arc);
}
macro_rules! tuple_len { ($($ty:ident),+) => { [$(stringify!($ty)),+].len() }; }
macro_rules! tuples {
($($ty:ident:$index:tt),+) => {
impl<$($ty: ValueDecode),+> ValueDecode for ($($ty,)+) {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Record { shape: RecordShape::Tuple, fields: { const LEN: usize = tuple_len!($($ty),+); &[$(
ValueDecodeField { selector: FieldSelector::Index { index: $index, declared_fields: LEN }, declaration_index: $index, value: ValueDecodeRef::of::<$ty>() }
),+] } };
}
};
}
tuples!(A:0);
tuples!(A:0,B:1);
tuples!(A:0,B:1,C:2);
tuples!(A:0,B:1,C:2,D:3);
tuples!(A:0,B:1,C:2,D:3,E:4);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10);
tuples!(A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10,L:11);
#[cfg(feature = "std")]
mod standard {
use super::*;
use std::collections::{HashMap, HashSet};
impl<K: ValueDecode, V: ValueDecode, S: 'static> ValueDecode for HashMap<K, V, S> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Map {
key: ValueDecodeRef::of::<K>(),
value: ValueDecodeRef::of::<V>(),
};
}
impl<T: ValueDecode, S: 'static> ValueDecode for HashSet<T, S> {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Sequence {
element: ValueDecodeRef::of::<T>(),
count: Scalar::U64,
capacity: None,
};
}
}
macro_rules! encode_description_kind {
($ty:ident, {$($variant:ident = $id:literal,)+}) => {
impl crate::Encode for $ty {
fn encode<E: crate::enc::Encoder>(&self, encoder: &mut E) -> Result<(), crate::error::EncodeError> {
(*self as u32).encode(encoder)
}
}
impl<Context> crate::Decode<Context> for $ty {
fn decode<D: crate::de::Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, crate::error::DecodeError> {
match <u32 as crate::Decode<Context>>::decode(decoder)? {
$($id => Ok(Self::$variant),)+
found => Err(crate::error::DecodeError::UnexpectedVariant {
type_name: core::any::type_name::<Self>(),
allowed: &crate::error::AllowedEnumVariants::Allowed(&[$($id,)+]),
found,
}),
}
}
}
crate::impl_borrow_decode!($ty);
impl ValueDecode for $ty {
const DECODE: &'static ValueDecodeSpec = &ValueDecodeSpec::Enum {
tag: Scalar::U32,
variants: &[$(ValueDecodeVariant {
tag: $id,
name: stringify!($variant),
shape: RecordShape::Unit,
fields: &[],
},)+],
};
}
};
}
encode_description_kind!(Scalar, {
Bool = 0,
U8 = 1,
U16 = 2,
U32 = 3,
U64 = 4,
U128 = 5,
I8 = 6,
I16 = 7,
I32 = 8,
I64 = 9,
I128 = 10,
F32 = 11,
F64 = 12,
Char = 13,
});
encode_description_kind!(RecordShape, {
Unit = 0,
Tuple = 1,
Newtype = 2,
Struct = 3,
});
impl crate::Encode for ValueMetadata {
fn encode<E: crate::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), crate::error::EncodeError> {
self.kind_id().encode(encoder)?;
match *self {
ValueMetadata::Quantity(quantity) => {
let mut bytes = [0; 8];
bytes[..4].copy_from_slice(&quantity.quantity().id().to_le_bytes());
bytes[4..].copy_from_slice(&quantity.storage_unit().id().to_le_bytes());
bytes.as_slice().encode(encoder)
}
}
}
}