Merge pull request #3 from BeFunctional/edsko/haskell-max-size
Introduce `HaskellMaxSize`
This commit is contained in:
commit
04f00f547b
4 changed files with 204 additions and 1 deletions
158
haskell-ffi/src/haskell_max_size.rs
Normal file
158
haskell-ffi/src/haskell_max_size.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
use std::{cmp::max, marker::PhantomData};
|
||||
|
||||
use crate::{derive_max_size_tuple_instance, fold_types, haskell_size::HaskellSize};
|
||||
|
||||
/*******************************************************************************
|
||||
Main class definition
|
||||
|
||||
TODO: We do not currently support deriving 'HaskellMaxSize'.
|
||||
*******************************************************************************/
|
||||
|
||||
pub trait HaskellMaxSize<Tag> {
|
||||
/// Statically known size (in bytes)
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Simple instances
|
||||
|
||||
These all just piggy-back on the `HaskellSize` instances.
|
||||
*******************************************************************************/
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for u8 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
u8::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for u16 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
u16::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for u32 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
u32::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for u64 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
u64::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for u128 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
u128::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for i8 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
i8::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for i16 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
i16::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for i32 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
i32::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for i64 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
i64::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for i128 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
i128::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for f32 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
f32::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for f64 {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
f64::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> HaskellMaxSize<Tag> for () {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
<()>::haskell_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Composite instances
|
||||
|
||||
See comments in `instances.rs` regarding `Result`
|
||||
*******************************************************************************/
|
||||
|
||||
impl<Tag, T: HaskellMaxSize<Tag>, const N: usize> HaskellMaxSize<Tag> for [T; N] {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
T::haskell_max_size(tag) * N
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag, T: HaskellMaxSize<Tag>> HaskellMaxSize<Tag> for Option<T> {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
1 + T::haskell_max_size(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag, T: HaskellMaxSize<Tag>, E: HaskellMaxSize<Tag>> HaskellMaxSize<Tag> for Result<T, E> {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
1 + max(T::haskell_max_size(tag), E::haskell_max_size(tag))
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Tuples
|
||||
|
||||
We support the same sizes of tuples as `borsh` does.
|
||||
*******************************************************************************/
|
||||
|
||||
derive_max_size_tuple_instance!(T0, T1);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
|
||||
derive_max_size_tuple_instance!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
|
||||
derive_max_size_tuple_instance!(
|
||||
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
|
||||
);
|
||||
derive_max_size_tuple_instance!(
|
||||
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
|
||||
);
|
||||
derive_max_size_tuple_instance!(
|
||||
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17
|
||||
);
|
||||
derive_max_size_tuple_instance!(
|
||||
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18
|
||||
);
|
||||
derive_max_size_tuple_instance!(
|
||||
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
|
||||
);
|
|
@ -8,6 +8,7 @@ pub mod bincode;
|
|||
pub mod deriving_via;
|
||||
pub mod error;
|
||||
pub mod from_haskell;
|
||||
pub mod haskell_max_size;
|
||||
pub mod haskell_size;
|
||||
pub mod to_haskell;
|
||||
pub mod use_borsh;
|
||||
|
|
|
@ -188,3 +188,15 @@ macro_rules! derive_size_tuple_instance {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Derive `HaskellMaxSize` instance for tuple with the specified type arguments.
|
||||
#[macro_export]
|
||||
macro_rules! derive_max_size_tuple_instance {
|
||||
($($ts:ident),*) => {
|
||||
impl<Tag, $($ts: HaskellMaxSize<Tag> ),* > HaskellMaxSize<Tag> for ( $($ts),* ) {
|
||||
fn haskell_max_size(tag: PhantomData<Tag>) -> usize {
|
||||
fold_types!( [ $($ts),* ], haskell_max_size, tag, +, 0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{fmt::Display, io::Write, marker::PhantomData};
|
||||
|
||||
use crate::{error::Result, HaskellSize};
|
||||
use crate::{error::Result, haskell_max_size::HaskellMaxSize, HaskellSize};
|
||||
|
||||
/*******************************************************************************
|
||||
Main class definition
|
||||
|
@ -61,6 +61,38 @@ where
|
|||
} else {
|
||||
let mut out_len_copy = out_len;
|
||||
marshall_to_haskell_var(t, out, &mut out_len_copy, tag);
|
||||
if out_len_copy != expected_len {
|
||||
panic!(
|
||||
"marshall_to_haskell_fixed: got buffer of expected size {}, but needed {}; bug in HaskellSize instance?",
|
||||
expected_len, out_len_copy
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marshall value with encoding of known maximum size
|
||||
///
|
||||
/// The `out_len` parameter is only used to verify that the Haskell-side and
|
||||
/// the Rust side agree on the length of the encoding.
|
||||
pub fn marshall_to_haskell_max<Tag, T>(t: &T, out: *mut u8, out_len: usize, tag: PhantomData<Tag>)
|
||||
where
|
||||
T: HaskellMaxSize<Tag> + ToHaskell<Tag>,
|
||||
{
|
||||
let max_len: usize = T::haskell_max_size(tag);
|
||||
if out_len != max_len {
|
||||
panic!(
|
||||
"marshall_to_haskell_max: expected buffer of size {}, but got {}",
|
||||
max_len, out_len
|
||||
)
|
||||
} else {
|
||||
let mut out_len_copy = out_len;
|
||||
marshall_to_haskell_var(t, out, &mut out_len_copy, tag);
|
||||
if out_len_copy > max_len {
|
||||
panic!(
|
||||
"marshall_to_haskell_max: required size {} exceeds maximum {}; bug in HaskellMaxSize instance?",
|
||||
out_len_copy, max_len
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue