Merge pull request #2 from BeFunctional/edsko/generalize-error

Use `std::error::Error` (not `std::io::Error`)
This commit is contained in:
Edsko de Vries 2023-03-21 15:43:10 +00:00 committed by GitHub
commit 792680d016
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 88 additions and 78 deletions

View file

@ -1,36 +1,37 @@
use std::{
io::{Error, ErrorKind, Write},
io::{ErrorKind, Write},
marker::PhantomData,
};
use crate::error::Result;
/// Implement `to_haskell` using `bincode`
///
/// The result will be length-prefixed ("bincode-in-Borsh").
pub fn bincode_to_haskell<Tag, T, W>(
t: &T,
writer: &mut W,
_: PhantomData<Tag>,
) -> Result<(), Error>
pub fn bincode_to_haskell<Tag, T, W>(t: &T, writer: &mut W, _: PhantomData<Tag>) -> Result<()>
where
T: serde::ser::Serialize,
W: Write,
{
match bincode::serialize(t) {
Ok(vec) => borsh::BorshSerialize::serialize(&vec, writer),
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
Ok(vec) => {
borsh::BorshSerialize::serialize(&vec, writer)?;
Ok(())
}
Err(e) => Err(Box::new(std::io::Error::new(ErrorKind::InvalidData, e))),
}
}
/// Implement `from_haskell` using `bincode`
///
/// See als `bincode_to_haskell`
pub fn bincode_from_haskell<Tag, T>(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<T, Error>
pub fn bincode_from_haskell<Tag, T>(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let vec: Vec<u8> = borsh::BorshDeserialize::deserialize(buf)?;
match bincode::deserialize(vec.as_ref()) {
Ok(x) => Ok(x),
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
Err(e) => Err(Box::new(std::io::Error::new(ErrorKind::InvalidData, e))),
}
}

View file

@ -4,7 +4,7 @@ use std::{
cmp::Ordering,
fmt::Debug,
hash::{Hash, Hasher},
io::{Error, Write},
io::Write,
marker::PhantomData,
};
@ -100,14 +100,20 @@ impl<Tag, T: Copy> Copy for Haskell<Tag, T> {}
*******************************************************************************/
impl<Tag, T: ToHaskell<Tag>> BorshSerialize for Haskell<Tag, T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
self.0.to_haskell(writer, PhantomData)
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
match self.0.to_haskell(writer, PhantomData) {
Ok(_) => Ok(()),
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
}
}
impl<Tag, T: FromHaskell<Tag>> BorshDeserialize for Haskell<Tag, T> {
fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
let tag: PhantomData<Tag> = PhantomData;
T::from_haskell(buf, tag).map(tag_val)
match T::from_haskell(buf, tag).map(tag_val) {
Ok(x) => Ok(x),
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
}
}

2
haskell-ffi/src/error.rs Normal file
View file

@ -0,0 +1,2 @@
pub type Error = Box<dyn std::error::Error + Send + Sync>;
pub type Result<T> = core::result::Result<T, Error>;

View file

@ -1,9 +1,6 @@
use std::{
io::{Error, ErrorKind},
marker::PhantomData,
};
use std::{io::ErrorKind, marker::PhantomData};
use crate::HaskellSize;
use crate::{error::Error, HaskellSize};
/*******************************************************************************
Main class definition
@ -23,7 +20,10 @@ pub trait FromHaskell<Tag>: Sized {
let mut slice_mut = slice;
let result = Self::from_haskell(&mut slice_mut, tag)?;
if !slice_mut.is_empty() {
return Err(Error::new(ErrorKind::InvalidData, ERROR_NOT_ALL_BYTES_READ));
return Err(Box::new(std::io::Error::new(
ErrorKind::InvalidData,
ERROR_NOT_ALL_BYTES_READ,
)));
}
Ok(result)
}

View file

@ -7,13 +7,14 @@ use borsh::{BorshDeserialize, BorshSerialize};
use std::{
collections::{HashMap, HashSet},
hash::Hash,
io::{Error, ErrorKind, Write},
io::{ErrorKind, Write},
marker::PhantomData,
};
use crate::{
derive_array_instances, derive_simple_instances, derive_tuple_instances,
deriving_via::{tag_ref, untag_val, Haskell},
error::Result,
from_haskell::FromHaskell,
map_tuple, map_tuple_ref,
to_haskell::ToHaskell,
@ -125,14 +126,15 @@ derive_tuple_instances!(
*******************************************************************************/
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for Vec<T> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
let tagged: Vec<&Haskell<Tag, T>> = self.iter().map(tag_ref).collect();
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
impl<Tag, T: FromHaskell<Tag>> FromHaskell<Tag> for Vec<T> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: Vec<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
Ok(tagged.into_iter().map(untag_val).collect())
}
@ -147,10 +149,11 @@ where
K: Eq + PartialOrd + Hash + ToHaskell<Tag>,
V: ToHaskell<Tag>,
{
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
let tagged: HashMap<&Haskell<Tag, K>, &Haskell<Tag, V>> =
self.iter().map(|(k, v)| (tag_ref(k), tag_ref(v))).collect();
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
@ -159,7 +162,7 @@ where
K: Eq + Hash + FromHaskell<Tag>,
V: FromHaskell<Tag>,
{
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: HashMap<Haskell<Tag, K>, Haskell<Tag, V>> = BorshDeserialize::deserialize(buf)?;
Ok(tagged
.into_iter()
@ -176,9 +179,10 @@ impl<Tag, T> ToHaskell<Tag> for HashSet<T>
where
T: Eq + PartialOrd + Hash + ToHaskell<Tag>,
{
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
let tagged: HashSet<&Haskell<Tag, T>> = self.iter().map(tag_ref).collect();
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
@ -186,7 +190,7 @@ impl<Tag, T> FromHaskell<Tag> for HashSet<T>
where
T: Eq + Hash + FromHaskell<Tag>,
{
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: HashSet<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
Ok(tagged.into_iter().map(untag_val).collect())
}
@ -197,14 +201,15 @@ where
*******************************************************************************/
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for Option<T> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
let tagged: Option<&Haskell<Tag, T>> = self.as_ref().map(tag_ref);
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
impl<Tag, T: FromHaskell<Tag>> FromHaskell<Tag> for Option<T> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: Option<Haskell<Tag, T>> = BorshDeserialize::deserialize(buf)?;
Ok(tagged.map(untag_val))
}
@ -220,13 +225,14 @@ impl<Tag, T: FromHaskell<Tag>> FromHaskell<Tag> for Option<T> {
the result of some Rust-side operation.
*******************************************************************************/
impl<Tag, T: ToHaskell<Tag>, E: ToHaskell<Tag>> ToHaskell<Tag> for Result<T, E> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
let tagged: Result<&Haskell<Tag, T>, &Haskell<Tag, E>> = match self {
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 {
Ok(t) => Ok(tag_ref(t)),
Err(e) => Err(tag_ref(e)),
};
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
@ -244,19 +250,22 @@ impl<Tag> HaskellSize<Tag> for bool {
}
impl<Tag> ToHaskell<Tag> for bool {
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<()> {
let as_u8: u8 = if *self { 1 } else { 0 };
as_u8.to_haskell(writer, tag)
}
}
impl<Tag> FromHaskell<Tag> for bool {
fn from_haskell(buf: &mut &[u8], tag: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], tag: PhantomData<Tag>) -> Result<Self> {
let as_u8 = u8::from_haskell(buf, tag)?;
match as_u8 {
0 => Ok(false),
1 => Ok(true),
_ => Err(Error::new(ErrorKind::InvalidData, "Invalid bool")),
_ => Err(Box::new(std::io::Error::new(
ErrorKind::InvalidData,
"Invalid bool",
))),
}
}
}

View file

@ -6,6 +6,7 @@ mod macros;
pub mod bincode;
pub mod deriving_via;
pub mod error;
pub mod from_haskell;
pub mod haskell_size;
pub mod to_haskell;

View file

@ -119,18 +119,16 @@ macro_rules! fold_types {
macro_rules! derive_simple_instances {
($t:ty) => {
impl<Tag> ToHaskell<Tag> for $t {
fn to_haskell<W: Write>(
&self,
writer: &mut W,
_: PhantomData<Tag>,
) -> Result<(), Error> {
self.serialize(writer)
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl<Tag> FromHaskell<Tag> for $t {
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<Tag>) -> Result<Self, Error> {
<$t>::deserialize(buf)
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<Tag>) -> Result<Self> {
let x = <$t>::deserialize(buf)?;
Ok(x)
}
}
};
@ -141,18 +139,15 @@ macro_rules! derive_simple_instances {
macro_rules! derive_array_instances {
($sz : literal) => {
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for [T; $sz] {
fn to_haskell<W: Write>(
&self,
writer: &mut W,
_: PhantomData<Tag>,
) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
let tagged: [&Haskell<Tag, T>; $sz] = self.each_ref().map(tag_ref);
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
impl<Tag, T: FromHaskell<Tag> + Default + Copy> FromHaskell<Tag> for [T; $sz] {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: [Haskell<Tag, T>; $sz] = BorshDeserialize::deserialize(buf)?;
Ok(tagged.map(untag_val))
}
@ -166,14 +161,15 @@ macro_rules! derive_array_instances {
macro_rules! derive_tuple_instances {
($($ts:ident),*) => {
impl<Tag, $($ts: ToHaskell<Tag> ),* > ToHaskell<Tag> for ( $($ts ),* ) {
fn to_haskell<W: Write>(&self, writer: &mut W,_: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W,_: PhantomData<Tag>) -> Result<()> {
let tagged: ( $(&Haskell<Tag, $ts> ),* ) = map_tuple_ref!( [ $($ts),* ], self, tag_ref );
tagged.serialize(writer)
tagged.serialize(writer)?;
Ok(())
}
}
impl<Tag, $($ts: FromHaskell<Tag> ),* > FromHaskell<Tag> for ( $($ts ),* ) {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let tagged: ( $(Haskell<Tag, $ts> ),* ) = BorshDeserialize::deserialize(buf)?;
Ok( map_tuple!( [ $($ts),* ], tagged, untag_val ) )
}

View file

@ -1,10 +1,6 @@
use std::{
fmt::Display,
io::{Error, Write},
marker::PhantomData,
};
use std::{fmt::Display, io::Write, marker::PhantomData};
use crate::HaskellSize;
use crate::{error::Result, HaskellSize};
/*******************************************************************************
Main class definition
@ -23,9 +19,9 @@ pub trait ToHaskell<Tag> {
/// `solana-sdk-haskell` library can define a `ToHaskell` instance for
/// `Keypair`, defined in `solana-sdk`, as long as it uses a tag `Solana`
/// defined locally in the `solana-haskell-sdk` package.
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<(), Error>;
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<()>;
fn to_haskell_vec(&self, tag: PhantomData<Tag>) -> Result<Vec<u8>, Error> {
fn to_haskell_vec(&self, tag: PhantomData<Tag>) -> Result<Vec<u8>> {
let mut result = Vec::with_capacity(DEFAULT_SERIALIZER_CAPACITY);
self.to_haskell(&mut result, tag)?;
Ok(result)
@ -33,7 +29,7 @@ pub trait ToHaskell<Tag> {
}
impl<Tag, T: ToHaskell<Tag>> ToHaskell<Tag> for &T {
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<(), Error> {
fn to_haskell<W: Write>(&self, writer: &mut W, tag: PhantomData<Tag>) -> Result<()> {
(*self).to_haskell(writer, tag)
}
}
@ -95,7 +91,7 @@ pub fn marshall_to_haskell_var<Tag, T>(
/// Wrapper around `marshall_to_haskell_var` that calls `format` for errors
pub fn marshall_result_to_haskell_var<Tag, T, E>(
res: &Result<T, E>,
res: &core::result::Result<T, E>,
out: *mut u8,
out_len: &mut usize,
tag: PhantomData<Tag>,
@ -103,7 +99,7 @@ pub fn marshall_result_to_haskell_var<Tag, T, E>(
T: ToHaskell<Tag>,
E: Display,
{
let res: Result<&T, String> = match res {
let res: core::result::Result<&T, String> = match res {
Ok(t) => Ok(t),
Err(e) => Err(format!("{}", e)),
};

View file

@ -1,10 +1,7 @@
use borsh::{BorshDeserialize, BorshSerialize};
use std::{
io::{Error, Write},
marker::PhantomData,
};
use std::{io::Write, marker::PhantomData};
use crate::{FromHaskell, ToHaskell};
use crate::{error::Result, FromHaskell, ToHaskell};
/// Newtype wrapper for defaulting to `borsh` for `ToHaskell`/`FromHaskell`
///
@ -32,14 +29,16 @@ pub fn unwrap_use_borsh_ref<T>(use_borsh: &UseBorsh<T>) -> &T {
*******************************************************************************/
impl<Tag, T: BorshSerialize> ToHaskell<Tag> for UseBorsh<T> {
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<(), Error> {
unwrap_use_borsh_ref(self).serialize(writer)
fn to_haskell<W: Write>(&self, writer: &mut W, _: PhantomData<Tag>) -> Result<()> {
unwrap_use_borsh_ref(self).serialize(writer)?;
Ok(())
}
}
impl<Tag, T: BorshDeserialize> FromHaskell<Tag> for UseBorsh<T> {
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self, Error> {
T::deserialize(buf).map(UseBorsh)
fn from_haskell(buf: &mut &[u8], _: PhantomData<Tag>) -> Result<Self> {
let x = T::deserialize(buf).map(UseBorsh)?;
Ok(x)
}
}