use serde::{Serialize, de::DeserializeOwned};
#[derive(Clone, Copy, Debug)]
pub struct Shape {
pub bytes: usize,
pub heap: usize,
pub nodes: usize,
pub depth: usize,
}
impl Shape {
pub const fn scalar(bytes: usize) -> Self {
Self {
bytes,
heap: 0,
nodes: 1,
depth: 1,
}
}
pub const fn record(children: &[Self]) -> Self {
let mut out = Self::scalar(0);
let mut i = 0;
while i < children.len() {
let child = children[i];
out.bytes = out.bytes.saturating_add(child.bytes);
out.heap = out.heap.saturating_add(child.heap);
out.nodes = out.nodes.saturating_add(child.nodes);
let depth = child.depth.saturating_add(1);
if depth > out.depth {
out.depth = depth;
}
i += 1;
}
out
}
pub const fn choice(tag_bytes: usize, alternatives: &[Self]) -> Self {
let mut out = Self::scalar(0);
let mut i = 0;
while i < alternatives.len() {
let child = alternatives[i];
if child.bytes > out.bytes {
out.bytes = child.bytes;
}
if child.heap > out.heap {
out.heap = child.heap;
}
if child.nodes > out.nodes {
out.nodes = child.nodes;
}
if child.depth > out.depth {
out.depth = child.depth;
}
i += 1;
}
out.bytes = out.bytes.saturating_add(tag_bytes);
out.nodes = out.nodes.saturating_add(1);
out.depth = out.depth.saturating_add(1);
out
}
}
pub trait Wire: Serialize + DeserializeOwned {
const SHAPE: Shape;
const SCHEMA: crate::schema::Schema = crate::schema::Schema::Opaque;
}
#[derive(Clone, Copy, Debug)]
pub struct Limits {
pub bytes: usize,
pub allocation: usize,
pub nodes: usize,
pub depth: usize,
}
macro_rules! scalars {
($($ty:ty => ($bytes:expr, $schema:expr)),* $(,)?) => { $(
impl Wire for $ty {
const SHAPE: Shape = Shape::scalar($bytes);
const SCHEMA: crate::schema::Schema = $schema;
}
)* };
}
use crate::schema::Schema;
scalars! { () => (0, Schema::Unit), bool => (1, Schema::Bool),
u8 => (1, Schema::Unsigned(8)), i8 => (1, Schema::Signed(8)),
u16 => (3, Schema::Unsigned(16)), i16 => (3, Schema::Signed(16)),
u32 => (5, Schema::Unsigned(32)), i32 => (5, Schema::Signed(32)),
u64 => (10, Schema::Unsigned(64)), i64 => (10, Schema::Signed(64)),
u128 => (19, Schema::Unsigned(128)), i128 => (19, Schema::Signed(128)) }
impl<T: Wire> Wire for Option<T> {
const SHAPE: Shape = Shape::choice(1, &[T::SHAPE]);
const SCHEMA: Schema = Schema::Option(&T::SCHEMA);
}
impl<T: Wire, E: Wire> Wire for Result<T, E> {
const SHAPE: Shape = Shape::choice(1, &[T::SHAPE, E::SHAPE]);
const SCHEMA: Schema = Schema::Result(&T::SCHEMA, &E::SCHEMA);
}
impl<T: Wire, const N: usize> Wire for [T; N]
where
[T; N]: Serialize + DeserializeOwned,
{
const SCHEMA: Schema = Schema::Array(&T::SCHEMA, N);
const SHAPE: Shape = Shape {
bytes: T::SHAPE.bytes.saturating_mul(N),
heap: T::SHAPE.heap.saturating_mul(N),
nodes: 1_usize.saturating_add(T::SHAPE.nodes.saturating_mul(N)),
depth: T::SHAPE.depth.saturating_add(1),
};
}