From 7685f363e2b0fa12e71aee3cebd60036a64df9f5 Mon Sep 17 00:00:00 2001 From: Edsko de Vries Date: Tue, 21 Mar 2023 15:53:59 +0100 Subject: [PATCH] Use `std::error::Error` (not `std::io::Error`) This makes client code a bit easier to write, since we can then use `?;` in more situations to just cast any kind of error. --- haskell-ffi/src/bincode.rs | 21 +++++++------- haskell-ffi/src/deriving_via.rs | 14 +++++++--- haskell-ffi/src/error.rs | 2 ++ haskell-ffi/src/from_haskell.rs | 12 ++++---- haskell-ffi/src/instances.rs | 49 +++++++++++++++++++-------------- haskell-ffi/src/lib.rs | 1 + haskell-ffi/src/macros.rs | 32 ++++++++++----------- haskell-ffi/src/to_haskell.rs | 18 +++++------- haskell-ffi/src/use_borsh.rs | 17 ++++++------ 9 files changed, 88 insertions(+), 78 deletions(-) create mode 100644 haskell-ffi/src/error.rs diff --git a/haskell-ffi/src/bincode.rs b/haskell-ffi/src/bincode.rs index 86ec825..ba5bc69 100644 --- a/haskell-ffi/src/bincode.rs +++ b/haskell-ffi/src/bincode.rs @@ -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( - t: &T, - writer: &mut W, - _: PhantomData, -) -> Result<(), Error> +pub fn bincode_to_haskell(t: &T, writer: &mut W, _: PhantomData) -> 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(buf: &mut &[u8], _: PhantomData) -> Result +pub fn bincode_from_haskell(buf: &mut &[u8], _: PhantomData) -> Result where T: serde::de::DeserializeOwned, { let vec: Vec = 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))), } } diff --git a/haskell-ffi/src/deriving_via.rs b/haskell-ffi/src/deriving_via.rs index 2182360..3fc0bab 100644 --- a/haskell-ffi/src/deriving_via.rs +++ b/haskell-ffi/src/deriving_via.rs @@ -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 Copy for Haskell {} *******************************************************************************/ impl> BorshSerialize for Haskell { - fn serialize(&self, writer: &mut W) -> Result<(), Error> { - self.0.to_haskell(writer, PhantomData) + fn serialize(&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> BorshDeserialize for Haskell { fn deserialize(buf: &mut &[u8]) -> std::io::Result { let tag: PhantomData = 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)), + } } } diff --git a/haskell-ffi/src/error.rs b/haskell-ffi/src/error.rs new file mode 100644 index 0000000..3ba7993 --- /dev/null +++ b/haskell-ffi/src/error.rs @@ -0,0 +1,2 @@ +pub type Error = Box; +pub type Result = core::result::Result; diff --git a/haskell-ffi/src/from_haskell.rs b/haskell-ffi/src/from_haskell.rs index 277e539..32e4e58 100644 --- a/haskell-ffi/src/from_haskell.rs +++ b/haskell-ffi/src/from_haskell.rs @@ -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: 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) } diff --git a/haskell-ffi/src/instances.rs b/haskell-ffi/src/instances.rs index beed2b8..1474d6b 100644 --- a/haskell-ffi/src/instances.rs +++ b/haskell-ffi/src/instances.rs @@ -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> ToHaskell for Vec { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { let tagged: Vec<&Haskell> = self.iter().map(tag_ref).collect(); - tagged.serialize(writer) + tagged.serialize(writer)?; + Ok(()) } } impl> FromHaskell for Vec { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: Vec> = BorshDeserialize::deserialize(buf)?; Ok(tagged.into_iter().map(untag_val).collect()) } @@ -147,10 +149,11 @@ where K: Eq + PartialOrd + Hash + ToHaskell, V: ToHaskell, { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { let tagged: HashMap<&Haskell, &Haskell> = 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, V: FromHaskell, { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: HashMap, Haskell> = BorshDeserialize::deserialize(buf)?; Ok(tagged .into_iter() @@ -176,9 +179,10 @@ impl ToHaskell for HashSet where T: Eq + PartialOrd + Hash + ToHaskell, { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { let tagged: HashSet<&Haskell> = self.iter().map(tag_ref).collect(); - tagged.serialize(writer) + tagged.serialize(writer)?; + Ok(()) } } @@ -186,7 +190,7 @@ impl FromHaskell for HashSet where T: Eq + Hash + FromHaskell, { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: HashSet> = BorshDeserialize::deserialize(buf)?; Ok(tagged.into_iter().map(untag_val).collect()) } @@ -197,14 +201,15 @@ where *******************************************************************************/ impl> ToHaskell for Option { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { let tagged: Option<&Haskell> = self.as_ref().map(tag_ref); - tagged.serialize(writer) + tagged.serialize(writer)?; + Ok(()) } } impl> FromHaskell for Option { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: Option> = BorshDeserialize::deserialize(buf)?; Ok(tagged.map(untag_val)) } @@ -220,13 +225,14 @@ impl> FromHaskell for Option { the result of some Rust-side operation. *******************************************************************************/ -impl, E: ToHaskell> ToHaskell for Result { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { - let tagged: Result<&Haskell, &Haskell> = match self { +impl, E: ToHaskell> ToHaskell for core::result::Result { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { + let tagged: core::result::Result<&Haskell, &Haskell> = 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 HaskellSize for bool { } impl ToHaskell for bool { - fn to_haskell(&self, writer: &mut W, tag: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, tag: PhantomData) -> Result<()> { let as_u8: u8 = if *self { 1 } else { 0 }; as_u8.to_haskell(writer, tag) } } impl FromHaskell for bool { - fn from_haskell(buf: &mut &[u8], tag: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], tag: PhantomData) -> Result { 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", + ))), } } } diff --git a/haskell-ffi/src/lib.rs b/haskell-ffi/src/lib.rs index be325a3..231cff5 100644 --- a/haskell-ffi/src/lib.rs +++ b/haskell-ffi/src/lib.rs @@ -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; diff --git a/haskell-ffi/src/macros.rs b/haskell-ffi/src/macros.rs index e69d867..429b736 100644 --- a/haskell-ffi/src/macros.rs +++ b/haskell-ffi/src/macros.rs @@ -119,18 +119,16 @@ macro_rules! fold_types { macro_rules! derive_simple_instances { ($t:ty) => { impl ToHaskell for $t { - fn to_haskell( - &self, - writer: &mut W, - _: PhantomData, - ) -> Result<(), Error> { - self.serialize(writer) + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { + self.serialize(writer)?; + Ok(()) } } impl FromHaskell for $t { - fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { - <$t>::deserialize(buf) + fn from_haskell(buf: &mut &[u8], _tag: PhantomData) -> Result { + let x = <$t>::deserialize(buf)?; + Ok(x) } } }; @@ -141,18 +139,15 @@ macro_rules! derive_simple_instances { macro_rules! derive_array_instances { ($sz : literal) => { impl> ToHaskell for [T; $sz] { - fn to_haskell( - &self, - writer: &mut W, - _: PhantomData, - ) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { let tagged: [&Haskell; $sz] = self.each_ref().map(tag_ref); - tagged.serialize(writer) + tagged.serialize(writer)?; + Ok(()) } } impl + Default + Copy> FromHaskell for [T; $sz] { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: [Haskell; $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 ),* > ToHaskell for ( $($ts ),* ) { - fn to_haskell(&self, writer: &mut W,_: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W,_: PhantomData) -> Result<()> { let tagged: ( $(&Haskell ),* ) = map_tuple_ref!( [ $($ts),* ], self, tag_ref ); - tagged.serialize(writer) + tagged.serialize(writer)?; + Ok(()) } } impl ),* > FromHaskell for ( $($ts ),* ) { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { let tagged: ( $(Haskell ),* ) = BorshDeserialize::deserialize(buf)?; Ok( map_tuple!( [ $($ts),* ], tagged, untag_val ) ) } diff --git a/haskell-ffi/src/to_haskell.rs b/haskell-ffi/src/to_haskell.rs index 986b326..4375ada 100644 --- a/haskell-ffi/src/to_haskell.rs +++ b/haskell-ffi/src/to_haskell.rs @@ -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 { /// `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(&self, writer: &mut W, tag: PhantomData) -> Result<(), Error>; + fn to_haskell(&self, writer: &mut W, tag: PhantomData) -> Result<()>; - fn to_haskell_vec(&self, tag: PhantomData) -> Result, Error> { + fn to_haskell_vec(&self, tag: PhantomData) -> Result> { let mut result = Vec::with_capacity(DEFAULT_SERIALIZER_CAPACITY); self.to_haskell(&mut result, tag)?; Ok(result) @@ -33,7 +29,7 @@ pub trait ToHaskell { } impl> ToHaskell for &T { - fn to_haskell(&self, writer: &mut W, tag: PhantomData) -> Result<(), Error> { + fn to_haskell(&self, writer: &mut W, tag: PhantomData) -> Result<()> { (*self).to_haskell(writer, tag) } } @@ -95,7 +91,7 @@ pub fn marshall_to_haskell_var( /// Wrapper around `marshall_to_haskell_var` that calls `format` for errors pub fn marshall_result_to_haskell_var( - res: &Result, + res: &core::result::Result, out: *mut u8, out_len: &mut usize, tag: PhantomData, @@ -103,7 +99,7 @@ pub fn marshall_result_to_haskell_var( T: ToHaskell, 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)), }; diff --git a/haskell-ffi/src/use_borsh.rs b/haskell-ffi/src/use_borsh.rs index 04047f1..ec007e1 100644 --- a/haskell-ffi/src/use_borsh.rs +++ b/haskell-ffi/src/use_borsh.rs @@ -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(use_borsh: &UseBorsh) -> &T { *******************************************************************************/ impl ToHaskell for UseBorsh { - fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<(), Error> { - unwrap_use_borsh_ref(self).serialize(writer) + fn to_haskell(&self, writer: &mut W, _: PhantomData) -> Result<()> { + unwrap_use_borsh_ref(self).serialize(writer)?; + Ok(()) } } impl FromHaskell for UseBorsh { - fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { - T::deserialize(buf).map(UseBorsh) + fn from_haskell(buf: &mut &[u8], _: PhantomData) -> Result { + let x = T::deserialize(buf).map(UseBorsh)?; + Ok(x) } }