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 deriving_via;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod from_haskell;
|
pub mod from_haskell;
|
||||||
|
pub mod haskell_max_size;
|
||||||
pub mod haskell_size;
|
pub mod haskell_size;
|
||||||
pub mod to_haskell;
|
pub mod to_haskell;
|
||||||
pub mod use_borsh;
|
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 std::{fmt::Display, io::Write, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{error::Result, HaskellSize};
|
use crate::{error::Result, haskell_max_size::HaskellMaxSize, HaskellSize};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
Main class definition
|
Main class definition
|
||||||
|
@ -61,6 +61,38 @@ where
|
||||||
} else {
|
} else {
|
||||||
let mut out_len_copy = out_len;
|
let mut out_len_copy = out_len;
|
||||||
marshall_to_haskell_var(t, out, &mut out_len_copy, tag);
|
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