2023-03-17 08:22:04 +00:00
|
|
|
//! ToHaskell and FromHaskell instances for the various standard types mandated
|
|
|
|
//! by the [Borsh spec](https://borsh.io/), piggy-backing on the implementation
|
|
|
|
//! in the `borsh` crate. The only spec-described types _not_ provided are
|
|
|
|
//! user-defined structs and enums.
|
|
|
|
|
|
|
|
use borsh::{BorshDeserialize, BorshSerialize};
|
|
|
|
use std::{
|
|
|
|
collections::{HashMap, HashSet},
|
|
|
|
hash::Hash,
|
2023-03-21 14:53:59 +00:00
|
|
|
io::{ErrorKind, Write},
|
2023-03-17 08:22:04 +00:00
|
|
|
marker::PhantomData,
|
|
|
|
};
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
derive_array_instances, derive_simple_instances, derive_tuple_instances,
|
|
|
|
deriving_via::{tag_ref, untag_val, Haskell},
|
2023-03-21 14:53:59 +00:00
|
|
|
error::Result,
|
2023-03-17 08:22:04 +00:00
|
|
|
from_haskell::FromHaskell,
|
|
|
|
map_tuple, map_tuple_ref,
|
|
|
|
to_haskell::ToHaskell,
|
|
|
|
HaskellSize,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Simple (non-composite) instances
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
derive_simple_instances!(u8);
|
|
|
|
derive_simple_instances!(u16);
|
|
|
|
derive_simple_instances!(u32);
|
|
|
|
derive_simple_instances!(u64);
|
|
|
|
derive_simple_instances!(u128);
|
|
|
|
derive_simple_instances!(i8);
|
|
|
|
derive_simple_instances!(i16);
|
|
|
|
derive_simple_instances!(i32);
|
|
|
|
derive_simple_instances!(i64);
|
|
|
|
derive_simple_instances!(i128);
|
|
|
|
derive_simple_instances!(f32);
|
|
|
|
derive_simple_instances!(f64);
|
|
|
|
derive_simple_instances!(());
|
|
|
|
derive_simple_instances!(String);
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Array instances
|
|
|
|
|
|
|
|
This is the same set of sizes as supported by borsh.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
derive_array_instances!(0);
|
|
|
|
derive_array_instances!(1);
|
|
|
|
derive_array_instances!(2);
|
|
|
|
derive_array_instances!(3);
|
|
|
|
derive_array_instances!(4);
|
|
|
|
derive_array_instances!(5);
|
|
|
|
derive_array_instances!(6);
|
|
|
|
derive_array_instances!(7);
|
|
|
|
derive_array_instances!(8);
|
|
|
|
derive_array_instances!(9);
|
|
|
|
derive_array_instances!(10);
|
|
|
|
derive_array_instances!(11);
|
|
|
|
derive_array_instances!(12);
|
|
|
|
derive_array_instances!(13);
|
|
|
|
derive_array_instances!(14);
|
|
|
|
derive_array_instances!(15);
|
|
|
|
derive_array_instances!(16);
|
|
|
|
derive_array_instances!(17);
|
|
|
|
derive_array_instances!(18);
|
|
|
|
derive_array_instances!(19);
|
|
|
|
derive_array_instances!(20);
|
|
|
|
derive_array_instances!(21);
|
|
|
|
derive_array_instances!(22);
|
|
|
|
derive_array_instances!(23);
|
|
|
|
derive_array_instances!(24);
|
|
|
|
derive_array_instances!(25);
|
|
|
|
derive_array_instances!(26);
|
|
|
|
derive_array_instances!(27);
|
|
|
|
derive_array_instances!(28);
|
|
|
|
derive_array_instances!(29);
|
|
|
|
derive_array_instances!(30);
|
|
|
|
derive_array_instances!(31);
|
|
|
|
derive_array_instances!(32);
|
|
|
|
|
|
|
|
derive_array_instances!(64);
|
|
|
|
derive_array_instances!(65);
|
|
|
|
|
|
|
|
derive_array_instances!(128);
|
|
|
|
derive_array_instances!(256);
|
|
|
|
derive_array_instances!(512);
|
|
|
|
derive_array_instances!(1024);
|
|
|
|
derive_array_instances!(2048);
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Composite instances
|
|
|
|
|
|
|
|
This is the same set of tuple sizes as supported by `borsh.`
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
derive_tuple_instances!(T0, T1);
|
|
|
|
derive_tuple_instances!(T0, T1, T2);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
|
|
|
|
derive_tuple_instances!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
|
|
|
|
derive_tuple_instances!(
|
|
|
|
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17
|
|
|
|
);
|
|
|
|
derive_tuple_instances!(
|
|
|
|
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18
|
|
|
|
);
|
|
|
|
derive_tuple_instances!(
|
|
|
|
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
|
|
|
|
);
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Vec
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for Vec<T> {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: Vec<&Haskell<Tag, T>> = self.iter().map(tag_ref).collect();
|
2023-03-21 14:53:59 +00:00
|
|
|
tagged.serialize(writer)?;
|
|
|
|
Ok(())
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag, T: FromHaskell<Tag>> FromHaskell<Tag> for Vec<T> {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: Vec<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
|
|
|
|
Ok(tagged.into_iter().map(untag_val).collect())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
HashMap
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
impl<Tag, K, V> ToHaskell<Tag> for HashMap<K, V>
|
|
|
|
where
|
|
|
|
K: Eq + PartialOrd + Hash + ToHaskell<Tag>,
|
|
|
|
V: ToHaskell<Tag>,
|
|
|
|
{
|
2023-03-21 14:53:59 +00:00
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: HashMap<&Haskell<Tag, K>, &Haskell<Tag, V>> =
|
|
|
|
self.iter().map(|(k, v)| (tag_ref(k), tag_ref(v))).collect();
|
2023-03-21 14:53:59 +00:00
|
|
|
tagged.serialize(writer)?;
|
|
|
|
Ok(())
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag, K, V> FromHaskell<Tag> for HashMap<K, V>
|
|
|
|
where
|
|
|
|
K: Eq + Hash + FromHaskell<Tag>,
|
|
|
|
V: FromHaskell<Tag>,
|
|
|
|
{
|
2023-03-21 14:53:59 +00:00
|
|
|
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: HashMap<Haskell<Tag, K>, Haskell<Tag, V>> = BorshDeserialize::deserialize(buf)?;
|
|
|
|
Ok(tagged
|
|
|
|
.into_iter()
|
|
|
|
.map(|(k, v)| (untag_val(k), untag_val(v)))
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
HashSet
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
impl<Tag, T> ToHaskell<Tag> for HashSet<T>
|
|
|
|
where
|
|
|
|
T: Eq + PartialOrd + Hash + ToHaskell<Tag>,
|
|
|
|
{
|
2023-03-21 14:53:59 +00:00
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: HashSet<&Haskell<Tag, T>> = self.iter().map(tag_ref).collect();
|
2023-03-21 14:53:59 +00:00
|
|
|
tagged.serialize(writer)?;
|
|
|
|
Ok(())
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag, T> FromHaskell<Tag> for HashSet<T>
|
|
|
|
where
|
|
|
|
T: Eq + Hash + FromHaskell<Tag>,
|
|
|
|
{
|
2023-03-21 14:53:59 +00:00
|
|
|
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: HashSet<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
|
|
|
|
Ok(tagged.into_iter().map(untag_val).collect())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Option
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for Option<T> {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: Option<&Haskell<Tag, T>> = self.as_ref().map(tag_ref);
|
2023-03-21 14:53:59 +00:00
|
|
|
tagged.serialize(writer)?;
|
|
|
|
Ok(())
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag, T: FromHaskell<Tag>> FromHaskell<Tag> for Option<T> {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let tagged: Option<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
|
|
|
|
Ok(tagged.map(untag_val))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Result
|
|
|
|
|
|
|
|
`Result` is not explicitly mentioned by the Borsh spec, but it's ubiquitous
|
|
|
|
and so we provide an instance for it, following the standard rule for enum.
|
|
|
|
|
|
|
|
There is no need for an instance of `FromHaskell`, since this is indicating
|
|
|
|
the result of some Rust-side operation.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
2023-03-21 14:53:59 +00:00
|
|
|
impl<Tag, T: ToHaskell<Tag>, E: ToHaskell<Tag>> ToHaskell<Tag> for core::result::Result<T, E> {
|
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
|
|
|
|
let tagged: core::result::Result<&Haskell<Tag, T>, &Haskell<Tag, E>> = match self {
|
2023-03-17 08:22:04 +00:00
|
|
|
Ok(t) => Ok(tag_ref(t)),
|
|
|
|
Err(e) => Err(tag_ref(e)),
|
|
|
|
};
|
2023-03-21 14:53:59 +00:00
|
|
|
tagged.serialize(writer)?;
|
|
|
|
Ok(())
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Bool
|
|
|
|
|
|
|
|
The Borsh spec does not mention Bool; we encode `true` as 1 and `false` as 0;
|
|
|
|
this matches what the Haskell `borsh` library does.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
impl<Tag> HaskellSize<Tag> for bool {
|
|
|
|
fn haskell_size(tag: PhantomData<Tag>) -> usize {
|
|
|
|
u8::haskell_size(tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag> ToHaskell<Tag> for bool {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<()> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let as_u8: u8 = if *self { 1 } else { 0 };
|
|
|
|
as_u8.to_haskell(writer, tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Tag> FromHaskell<Tag> for bool {
|
2023-03-21 14:53:59 +00:00
|
|
|
fn from_haskell(buf: &mut &[u8], tag: PhantomData<Tag>) -> Result<Self> {
|
2023-03-17 08:22:04 +00:00
|
|
|
let as_u8 = u8::from_haskell(buf, tag)?;
|
|
|
|
match as_u8 {
|
|
|
|
0 => Ok(false),
|
|
|
|
1 => Ok(true),
|
2023-03-21 14:53:59 +00:00
|
|
|
_ => Err(Box::new(std::io::Error::new(
|
|
|
|
ErrorKind::InvalidData,
|
|
|
|
"Invalid bool",
|
|
|
|
))),
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|