RLP 1.0.1 → 1.1.0
raw patch · 6 files changed
+293/−104 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.Serialize.RLP: instance Data.Serialize.RLP.RLPSerialize a => Data.Serialize.RLP.RLPSerialize (GHC.Maybe.Maybe a)
- Data.Serialize.RLP: fromBigEndian :: ByteString -> Int
+ Data.Serialize.RLP: fromBigEndian :: ByteString -> Either String Int
- Data.Serialize.RLP: fromBigEndianS :: ByteString -> Int
+ Data.Serialize.RLP: fromBigEndianS :: ByteString -> Either String Int
- Data.Serialize.RLP: fromRLP :: RLPSerialize a => RLPT -> a
+ Data.Serialize.RLP: fromRLP :: RLPSerialize a => RLPT -> Maybe a
- Data.Serialize.RLP: rlpDecode :: RLPSerialize a => ByteString -> Maybe a
+ Data.Serialize.RLP: rlpDecode :: RLPSerialize a => ByteString -> Either String a
Files
- ChangeLog.md +8/−0
- README.md +9/−1
- RLP.cabal +1/−1
- src/Data/Serialize/RLP.hs +147/−49
- src/Data/Serialize/RLP/Internal.hs +100/−28
- test/Data/Serialize/RLPSpec.hs +28/−25
ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for RLP +## 1.1.0 -- 2018-12-10++* Added error handling support. Check the generated haddock documentation where examples have been placed.++## 1.0.1 -- 2018-12-04++* Just added support for strings on the default types that are already instances of `RLPSerialize`+ ## 1.0.0 -- 2018-12-01 * First version.
README.md view
@@ -9,4 +9,12 @@ For more information, please check the haddock documentation (can be generated running `cabal haddock` on the root of the repo). -Feel free to contribute.+## Installation++On 1.1.0 error handling was coded as a safe way to fail on the decoding through Eithers. Usage of >=1.1 is quite advised.++Installation can be easily done through `cabal` as the package is in Hackage. `cabal install RLP` should be enough.++## Contribuition++Feel free to contribute. I think the error handling part could be improved.
RLP.cabal view
@@ -1,5 +1,5 @@ Name: RLP-Version: 1.0.1+Version: 1.1.0 Author: Javier Sagredo <jasataco@gmail.com> Maintainer: Javier Sagredo <jasataco@gmail.com> License: LGPL-3
src/Data/Serialize/RLP.hs view
@@ -37,6 +37,9 @@ -- * Example -- $example + -- * Errors and special cases+ -- $failexample+ ) where import Data.Serialize.RLP.Internal@@ -64,10 +67,14 @@ -- understanding of the generated code. -- -- It is important to remark that although it can't be imposed, it doesn't make sense to try--- to transform to RLP types with more than one constructor. The transformation should encode+-- to transform to RLP types with more than one constructor that don't difer in structure.+-- The transformation should encode -- a way to find out which of the constructors belongs to the data so not only data is being -- encoded in the result, also information about the structure futher than the actual length -- prefixes. That's why it only makes sense to transform to RLP types with just one constructor.+-- On the other hand, it's perfectly viable to encode types with more than one constructor if+-- the structure of each of them is different as it can be adjusted via pattern matching+-- strategies. -------------------------------------------------------------------------------- @@ -75,7 +82,7 @@ -- For encoding and decoding values with the RLP protocol, 'toRLP' and 'fromRLP' have to -- be implemented. ----- Instances of RLPSerialize have to satisfy the following property:+-- Instances of RLPSerialize are expected to satisfy the following property: -- -- > fromRLP . toRLP == id --@@ -88,8 +95,9 @@ class RLPSerialize a where -- | Transform a value to the 'RLPT' structure that best fits its internal structure toRLP :: a -> RLPT- -- | Transform an 'RLPT' structure back into the value it represents- fromRLP :: RLPT -> a+ -- | Transform an 'RLPT' structure back into the value it represents.+ -- Its return type is 'Maybe a' because it can fail+ fromRLP :: RLPT -> Maybe a -- | Transform a value to an 'RLPT' structure and then encode it following the -- RLP standard.@@ -97,9 +105,15 @@ rlpEncode = rlpEncodeI . toRLP -- | Transform a ByteString to an 'RLPT' structure following the RLP standard and- -- then transform it to the original type.- rlpDecode :: DBSL.ByteString -> Maybe a- rlpDecode x = maybe Nothing fromRLP $ rlpDecodeI x+ -- then transform it to the original type. It returns 'Left s' when failing on the+ -- decoding of the transforming from RLPT into the required type, and 'Right v' on+ -- success.+ rlpDecode :: DBSL.ByteString -> Either String a+ rlpDecode x = case rlpDecodeI x :: Either String RLPT of+ Left m -> Left m+ Right v -> case fromRLP v of+ Nothing -> Left "RLPT value couldn't ve transformed into the required type"+ Just v' -> Right v' {-# MINIMAL toRLP, fromRLP #-} @@ -107,15 +121,15 @@ instance RLPSerialize RLPT where toRLP = id - fromRLP = id+ fromRLP = Just . id -- ByteStrings just have to be encapsulated -- Also, it only makes sense to disencapsulate from a ByteString instance RLPSerialize DBS.ByteString where toRLP = RLPB - fromRLP (RLPB b) = b- fromRLP _ = undefined+ fromRLP (RLPB b) = Just b+ fromRLP _ = Nothing -- Ints have to be transformed into its Big-endian form -- and then they are treated as ByteStrings.@@ -125,15 +139,22 @@ instance RLPSerialize Int where toRLP = toRLP . toBigEndianS - fromRLP = fromBigEndianS . (fromRLP :: RLPT -> DBS.ByteString)+ fromRLP = maybe Nothing (\s -> case fromBigEndianS s of+ Left _ -> Nothing+ Right v -> Just v ) . (fromRLP :: RLPT -> Maybe DBS.ByteString) -- Serializing lists implies making a list with the serialization -- of each element instance {-# OVERLAPPABLE #-} RLPSerialize a => RLPSerialize [a] where toRLP = RLPL . map toRLP - fromRLP (RLPL x) = map fromRLP x- fromRLP _ = undefined+ fromRLP (RLPL x) = if any (\a -> case a of+ Nothing -> True+ _ -> False) r+ then Nothing+ else Just $ map unJust r+ where r = map fromRLP x+ fromRLP _ = Nothing -- Bools are serialized as [0] or [1] in a ByteArray -- THIS IS AN ASUMPTION considering Bool equivalent to@@ -143,59 +164,99 @@ toRLP False = RLPB $ toByteStringS "\NUL" fromRLP x- | x == toRLP True = True- | otherwise = False+ | x == toRLP True = Just True+ | x == toRLP False = Just False+ | otherwise = Nothing -- Strings are serialized as ByteStrings instance {-# OVERLAPPING #-} RLPSerialize String where toRLP = RLPB . toByteStringS - fromRLP (RLPB x) = fromByteStringS x- fromRLP _ = undefined+ fromRLP (RLPB x) = Just $ fromByteStringS x+ fromRLP _ = Nothing -- Chars are just length-one strings instance RLPSerialize Char where toRLP = RLPB . toByteStringS . (: []) - fromRLP (RLPB x) = head $ fromByteStringS x- fromRLP _ = undefined+ fromRLP (RLPB x) = Just $ head $ fromByteStringS x+ fromRLP _ = Nothing -- Tuples are transformed into Lists instance (RLPSerialize a, RLPSerialize b) => RLPSerialize (a, b) where toRLP (x, y) = RLPL [toRLP x, toRLP y] - fromRLP (RLPL [x, y]) = (fromRLP x, fromRLP y)- fromRLP _ = undefined+ fromRLP (RLPL [x, y]) =+ maybe Nothing+ (\x' -> maybe Nothing+ (\y' -> Just (x', y'))+ (fromRLP y))+ (fromRLP x)+ fromRLP _ = Nothing instance (RLPSerialize a, RLPSerialize b, RLPSerialize c) => RLPSerialize (a, b, c) where toRLP (x, y, z) = RLPL [toRLP x, toRLP y, toRLP z] - fromRLP (RLPL [x, y, z]) = (fromRLP x, fromRLP y, fromRLP z)- fromRLP _ = undefined-+ fromRLP (RLPL [x, y, z]) =+ maybe Nothing+ (\x' -> maybe Nothing+ (\y' -> maybe Nothing+ (\z' -> Just (x', y', z'))+ (fromRLP z))+ (fromRLP y))+ (fromRLP x)+ fromRLP _ = Nothing+ instance (RLPSerialize a, RLPSerialize b, RLPSerialize c, RLPSerialize d) => RLPSerialize (a, b, c, d) where toRLP (a1, a2, a3, a4) = RLPL [toRLP a1, toRLP a2, toRLP a3, toRLP a4] - fromRLP (RLPL [a1, a2, a3, a4]) = (fromRLP a1, fromRLP a2, fromRLP a3, fromRLP a4)- fromRLP _ = undefined+ fromRLP (RLPL [a1, a2, a3, a4]) =+ maybe Nothing+ (\a1' -> maybe Nothing+ (\a2' -> maybe Nothing+ (\a3' -> maybe Nothing+ (\a4' -> Just (a1', a2', a3', a4'))+ (fromRLP a4))+ (fromRLP a3))+ (fromRLP a2))+ (fromRLP a1)+ fromRLP _ = Nothing instance (RLPSerialize a, RLPSerialize b, RLPSerialize c, RLPSerialize d, RLPSerialize e) => RLPSerialize (a, b, c, d, e) where toRLP (a1, a2, a3, a4, a5) = RLPL [toRLP a1, toRLP a2, toRLP a3, toRLP a4, toRLP a5] - fromRLP (RLPL [a1, a2, a3, a4, a5]) = (fromRLP a1, fromRLP a2, fromRLP a3, fromRLP a4, fromRLP a5)- fromRLP _ = undefined+ fromRLP (RLPL [a1, a2, a3, a4, a5]) =+ maybe Nothing+ (\a1' -> maybe Nothing+ (\a2' -> maybe Nothing+ (\a3' -> maybe Nothing+ (\a4' -> maybe Nothing+ (\a5' -> Just (a1', a2', a3', a4', a5'))+ (fromRLP a5))+ (fromRLP a4))+ (fromRLP a3))+ (fromRLP a2))+ (fromRLP a1)+ fromRLP _ = Nothing instance (RLPSerialize a, RLPSerialize b, RLPSerialize c, RLPSerialize d, RLPSerialize e, RLPSerialize f) => RLPSerialize (a, b, c, d, e, f) where toRLP (a1, a2, a3, a4, a5, a6) = RLPL [toRLP a1, toRLP a2, toRLP a3, toRLP a4, toRLP a5, toRLP a6] - fromRLP (RLPL [a1, a2, a3, a4, a5, a6]) = (fromRLP a1, fromRLP a2, fromRLP a3, fromRLP a4, fromRLP a5, fromRLP a6)- fromRLP _ = undefined---- Needed by the default rlpDecode implementation-instance RLPSerialize a => RLPSerialize (Maybe a) where- toRLP = undefined-- fromRLP = Just . fromRLP+ fromRLP (RLPL [a1, a2, a3, a4, a5, a6]) =+ maybe Nothing+ (\a1' -> maybe Nothing+ (\a2' -> maybe Nothing+ (\a3' -> maybe Nothing+ (\a4' -> maybe Nothing+ (\a5' -> maybe Nothing+ (\a6' -> Just (a1', a2', a3', a4', a5', a6'))+ (fromRLP a6))+ (fromRLP a5))+ (fromRLP a4))+ (fromRLP a3))+ (fromRLP a2))+ (fromRLP a1)+ fromRLP _ = Nothing -------------------------------------------------------------------------------- @@ -213,24 +274,61 @@ -- -- Then we have to make it an instance of RLPSerialize: -- --- > instance RLPSerialize Person where--- > toRLP p = RLPL [--- > RLPL [--- > toRLP . toByteStringS . fst . name $ p,--- > toRLP . toByteStringS . snd . name $ p--- > ],--- > toRLP . age $ p]--- > --- > fromRLP (RLPL [ RLPL [ RLPB a, RLPB b ], RLPB c ]) =--- > Person (fromByteStringS a, fromByteStringS b) (fromBigEndianS c :: Int)+-- >instance RLPSerialize Person where+-- > toRLP p = RLPL [+-- > RLPL [+-- > toRLP . toByteStringS . fst . name $ p,+-- > toRLP . toByteStringS . snd . name $ p+-- > ],+-- > toRLP . age $ p]+-- >+-- > fromRLP (RLPL [ RLPL [ RLPB a, RLPB b ], RLPB c ]) =+-- > case fromBigEndianS c of+-- > Right v -> Just $ Person (fromByteStringS a, fromByteStringS b) v+-- > _ -> Nothing+-- > fromRLP _ = Nothing -- --- This way, if the decoding gives rise to other structure than the expected, a runtime--- exception will be thrown by the pattern matching. We can now use our decoder and encoder+-- This way, if the decoding gives rise to other structure than the expected, a the+-- resulting value would be 'Nothing'. We can now use our decoder and encoder -- with our custom type: -- -- > p = Person ("John", "Snow") 33 -- > e = rlpEncode p -- > -- "\204\202\132John\132Snow!" ~ [204,202,132,74,111,104,110,132,83,110,111,119,33] -- > rlpDecode e :: Maybe Person--- > -- Just (Person {name = ("John","Snow"), age = 33})+-- > -- Right (Person {name = ("John","Snow"), age = 33}) --++--------------------------------------------------------------------------------++-- $failexample+-- In case we run into an error situation, depending whether the RLPT structure is not well+-- formed or the generated structure couldn't be transformed into the expected type, an error+-- is returned in the form of a 'Left' value.+--+-- Just to see this as an example, if we chop the resulting ByteString, there's no way to+-- generate a correct RLPT structure so an error is thrown:+--+-- > rlpDecode $ DBSL.take 6 $ rlpEncode $ RLPL [ RLPB $ toByteStringS "John", RLPB $ toByteStringS "Snow" ] :: Either String RLPT+-- > -- Left "not enough bytes"+--+-- On the other hand, if we try to transform an incorrect value from the decoded RLPT we+-- generate a new error:+--+-- > rlpDecode $ rlpEncode $ RLPB $ toByteStringS "\STX" :: Either String Bool+-- > -- Left "RLPT value couldn't ve transformed into the required type"+--+-- If a ByteString is the result of the concatenation of more than one serialized RLPT structure,+-- only the first one would be decoded:+--+-- > rlpDecode $ rlpEncode $ RLPB $ toByteStringS "\STX" :: Either String Bool+-- > -- Left "RLPT value couldn't ve transformed into the required type"+--+-- If a ByteString is the result of the concatenation of more than one serialized RLPT structure,+-- only the first one would be decoded:+--+-- > a = rlpEncode $ RLPL [ RLPB $ toByteStringS "John", RLPB $ toByteStringS "Snow" ]+-- > b = DBSL.append a a+-- > -- "\202\132John\132Snow\202\132John\132Snow"+-- > rlpDecode b :: Either String RLPT+-- > -- Right (RLPL [RLPB "John",RLPB "Snow"])
src/Data/Serialize/RLP/Internal.hs view
@@ -12,6 +12,8 @@ toByteStringS, fromByteString, fromByteStringS,++ unJust, RLPT(..) ) where@@ -23,7 +25,9 @@ import qualified Data.ByteString.Char8 as DBSC import qualified Data.ByteString.Lazy as DBSL import qualified Data.ByteString.Lazy.Char8 as DBSLC+import qualified Data.List as DL + -------------------------------------------------------------------------------- -- | The 'RLPT' type represents the result of transforming the@@ -48,15 +52,18 @@ toBigEndianS :: Int -> DBS.ByteString toBigEndianS = DBSL.toStrict . toBigEndian -fromBigEndian :: DBSL.ByteString -> Int-fromBigEndian bs = fromIntegral . runGet getInt64be $ bs'+fromBigEndian :: DBSL.ByteString -> Either String Int+fromBigEndian bs = case bs'' of+ Left (_, _, msg) -> Left ("can't decode from Big-Endian: " ++ msg)+ Right (_, _, a) -> Right $ fromIntegral a where bs' = case () of _ | DBSL.length bs >= 8 -> bs | otherwise -> DBSLC.append (DBSLC.pack $ b) bs where b = take (8 - (fromIntegral . DBSL.length $ bs)) (repeat '\NUL')+ bs'' = runGetOrFail getInt64be $ bs' -- | Strict version of 'fromBigEndian'-fromBigEndianS :: DBS.ByteString -> Int+fromBigEndianS :: DBS.ByteString -> Either String Int fromBigEndianS = fromBigEndian . DBSL.fromStrict toByteString :: String -> DBSL.ByteString@@ -74,32 +81,64 @@ fromByteStringS = DBSC.unpack -- | Internal function for spliting the array in chunks of bytes-rlpSplit :: DBSL.ByteString -> [DBSL.ByteString]+rlpSplit :: DBSL.ByteString -> Either String [DBSL.ByteString] rlpSplit x- | DBSL.null x = []+ | DBSL.null x = Right [] | DBSL.head x < 192 = case () of- _ | DBSL.head x < 128 -> (DBSL.singleton . DBSL.head $ x) : (rlpSplit $ DBSL.tail x)+ _ | DBSL.head x < 128 ->+ let aux = rlpSplit $ DBSL.tail x in+ case aux of+ Left m -> Left m+ Right v -> Right $ (DBSL.singleton . DBSL.head $ x) : v | DBSL.head x < 183 -> let size = (fromIntegral $ DBSL.head x) - 128 :: Int in let total = size + 1 in- (DBSL.take (fromIntegral total) x) : (rlpSplit $ DBSL.drop (fromIntegral total) x)+ let aux = rlpSplit $ DBSL.drop (fromIntegral total) x in+ case aux of+ Left m -> Left m+ Right v -> Right $ (DBSL.take (fromIntegral total) x) : v | otherwise ->- let sizeSize = (fromIntegral $ DBSL.head x) - 183 :: Int in- let size = fromBigEndian . DBSL.take (fromIntegral sizeSize) . DBSL.tail $ x :: Int in- let total = sizeSize + size + 1 :: Int in - (DBSL.take (fromIntegral total) x) : (rlpSplit $ DBSL.drop (fromIntegral total) x)- | DBSL.head x == 192 = (DBSL.singleton $ DBSL.head x) : (rlpSplit $ DBSL.tail x)+ let sizeSize = (fromIntegral $ DBSL.head x) - 183 :: Int in+ let size = fromBigEndian . DBSL.take (fromIntegral sizeSize) . DBSL.tail $ x in+ case size of+ Left m -> Left m+ Right v ->+ let total = sizeSize + v + 1 :: Int in+ let aux = rlpSplit $ DBSL.drop (fromIntegral total) x in+ case aux of+ Left m -> Left m+ Right v' -> Right $ (DBSL.take (fromIntegral total) x) : v'+ | DBSL.head x == 192 =+ let aux = (rlpSplit $ DBSL.tail x) in+ case aux of+ Left m -> Left m+ Right v -> Right $ (DBSL.singleton $ DBSL.head x) : v | DBSL.head x < 247 = let size = (fromIntegral $ DBSL.head x) - 192 :: Int in let total = size + 1 in- (DBSL.take (fromIntegral total) x) : (rlpSplit $ DBSL.drop (fromIntegral total) x)+ let aux = rlpSplit $ DBSL.drop (fromIntegral total) x in+ case aux of+ Left m -> Left m+ Right v -> Right $ (DBSL.take (fromIntegral total) x) : v+ | otherwise = let sizeSize = (fromIntegral $ DBSL.head x) - 247 :: Int in- let size = fromBigEndian . DBSL.take (fromIntegral sizeSize) . DBSL.tail $ x :: Int in- let total = sizeSize + size + 1 :: Int in - (DBSL.take (fromIntegral total) x) : (rlpSplit $ DBSL.drop (fromIntegral total) x)+ let size = fromBigEndian . DBSL.take (fromIntegral sizeSize) . DBSL.tail $ x in+ case size of+ Left m -> Left m+ Right v -> + let total = sizeSize + v + 1 :: Int in+ let aux = rlpSplit $ DBSL.drop (fromIntegral total) x in+ case aux of+ Left m -> Left m+ Right v' -> Right $ (DBSL.take (fromIntegral total) x) : v' +-- Just for internal porpouses+unJust :: Maybe a -> a+unJust (Just x) = x+unJust _ = undefined+ -------------------------------------------------------------------------------- -- | The 'RLPEncodeable' class groups the RLPT, ByteString and Int types@@ -120,11 +159,11 @@ rlpDecodeI' :: Get a -- Mainly run rlpDecodeI'- rlpDecodeI :: DBSL.ByteString -> Maybe a+ rlpDecodeI :: DBSL.ByteString -> Either String a rlpDecodeI x = let r = runGetOrFail rlpDecodeI' x in case r of- Left _ -> Nothing- Right (_, _, s) -> Just s+ Left (_, _, m) -> Left m+ Right (_, _, s) -> Right s -------------------------------------------------------------------------------- -- Instances@@ -145,17 +184,43 @@ case () of _ | i < 192 -> do -- ByteArray ls <- getRemainingLazyByteString- return . RLPB . (\(Just x) -> x) . rlpDecodeI $ DBSL.cons i ls+ let r = rlpDecodeI $ DBSL.cons i ls+ case r of+ Left m -> fail m+ Right v -> return . RLPB $ v | i == 192 -> do -- Empty list return $ RLPL [] | i < 247 -> do -- Small list ls <- getLazyByteString . fromIntegral $ i - 192- return $ RLPL . map ((\(Just x) -> x) . rlpDecodeI) . rlpSplit $ ls+ let k = rlpSplit ls+ case k of+ Left m -> fail m+ Right v -> do+ let k' = map rlpDecodeI v+ let k'' = map (\e -> case e of+ Left m -> m+ Right _ -> "") k'+ case all null k'' of+ True -> return $ RLPL . map (\(Right x) -> x) $ k'+ _ -> fail (DL.intercalate ", " k'') | otherwise -> do -- Big List ls <- getLazyByteString . fromIntegral $ i - 247 let k = fromBigEndian ls- ls' <- getLazyByteString . fromIntegral $ k- return $ RLPL . map ((\(Just x) -> x) . rlpDecodeI) . rlpSplit $ ls'+ case k of+ Left m -> fail m+ Right v -> do+ ls' <- getLazyByteString . fromIntegral $ v+ let k' = rlpSplit ls'+ case k' of+ Left m' -> fail m'+ Right v' -> do+ let k'' = map rlpDecodeI v'+ let k'3 = map (\e -> case e of+ Left m -> m+ Right _ -> "") k''+ case all null k'3 of+ True -> return $ RLPL . map (\(Right x) -> x) $ k''+ _ -> fail (DL.intercalate ", " k'3) instance RLPEncodeable DBS.ByteString where rlpEncodeI' bs@@ -176,13 +241,20 @@ return ls | i < 192 -> do sbe <- getLazyByteString . fromIntegral $ i - 183- ls <- getByteString . fromBigEndian $ sbe- return ls- | otherwise -> undefined+ let k = fromBigEndian sbe+ case k of+ Left m -> fail m+ Right v -> do+ ls <- getByteString v+ return ls+ | otherwise -> fail "Decoding a ByteString with head >= 192" instance RLPEncodeable Int where- rlpEncodeI' = rlpEncodeI' . DBSL.toStrict . toBigEndian+ rlpEncodeI' = rlpEncodeI' . toBigEndianS rlpDecodeI' = do b <- rlpDecodeI' :: Get DBS.ByteString- return . fromBigEndian . DBSL.fromStrict $ b+ let k = fromBigEndianS b+ case k of+ Left m -> fail m+ Right v -> return v
test/Data/Serialize/RLPSpec.hs view
@@ -10,6 +10,9 @@ main :: IO () main = hspec spec +type ESB = Either String DBS.ByteString+type ESR = Either String RLPT+ spec :: Spec spec = do context "when encoding _empty_ values" $ do@@ -17,86 +20,86 @@ (DBSL.unpack . rlpEncode . toByteStringS $ "") `shouldBe` [ 0x80 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "" :: Maybe DBS.ByteString) `shouldBe` (Just $ toByteStringS "")+ (rlpDecode . rlpEncode . toByteStringS $ "" :: ESB) `shouldBe` Right (toByteStringS "") it "should encode the empty list" $ do (DBSL.unpack . rlpEncode . RLPL $ []) `shouldBe` [ 0xc0 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . RLPL $ [] :: Maybe RLPT) `shouldBe` (Just $ RLPL []) + (rlpDecode . rlpEncode . RLPL $ [] :: ESR) `shouldBe` Right (RLPL []) it "should encode the integer Zero" $ do (DBSL.unpack . rlpEncode . toRLP $ (0 :: Int)) `shouldBe` [ 0x80 ] it "should decode it back" $ do- (maybe Nothing fromRLP $ rlpDecode . rlpEncode . toRLP $ (0 :: Int) :: Maybe Int) `shouldBe` (Just 0)+ ((\(Right b) -> fromBigEndianS b) $ (rlpDecode . rlpEncode . toRLP $ (0 :: Int) :: ESB)) `shouldBe` (Right 0) context "when encoding ByteArrays" $ do it "should encode an array of length 1 and small value" $ do (DBSL.unpack . rlpEncode . toByteStringS $ "\NUL") `shouldBe` [ 0x00 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "\NUL" :: Maybe DBS.ByteString) `shouldBe` (Just $ toByteStringS "\NUL")+ (rlpDecode . rlpEncode . toByteStringS $ "\NUL" :: ESB) `shouldBe` Right (toByteStringS "\NUL") it "should encode an array of length 1 and big value" $ do (DBSL.unpack . rlpEncode . toByteStringS $ "\150") `shouldBe` [ 0x81, 0x96 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "\150" :: Maybe DBS.ByteString) `shouldBe` (Just $ toByteStringS "\150")+ (rlpDecode . rlpEncode . toByteStringS $ "\150" :: ESB) `shouldBe` Right (toByteStringS "\150") it "should encode an array of length bigger than one and smaller than 56" $ do (DBSL.unpack . rlpEncode . toByteStringS $ "\SOH\SOH") `shouldBe` [ 0x82, 0x01, 0x01 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "\SOH\SOH" :: Maybe DBS.ByteString) `shouldBe` (Just $ toByteStringS "\SOH\SOH")+ (rlpDecode . rlpEncode . toByteStringS $ "\SOH\SOH" :: ESB) `shouldBe` Right (toByteStringS "\SOH\SOH") it "should encode an array of length bigger than 56 with _small_ length" $ do (DBSL.unpack . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1) `shouldBe` ([ 0xb8, 0x3c ] ++ (Prelude.take 60 . Prelude.repeat $ 0x01)) it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 :: Maybe DBS.ByteString)- `shouldBe` (Just $ toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 0x01)+ (rlpDecode . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 :: ESB)+ `shouldBe` Right (toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 0x01) it "should encode an array of length bigger than 56 with _big_ length" $ do (DBSL.unpack . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 43520 . Prelude.repeat $ 1) `shouldBe` ([ 0xb9, 0xaa, 0x00 ] ++ (Prelude.take 43520 . Prelude.repeat $ 0x01)) it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 43520 . Prelude.repeat $ 1 :: Maybe DBS.ByteString)- `shouldBe` (Just $ toByteStringS . Prelude.map toEnum . Prelude.take 43520 . Prelude.repeat $ 0x01)+ (rlpDecode . rlpEncode . toByteStringS . Prelude.map toEnum . Prelude.take 43520 . Prelude.repeat $ 1 :: ESB)+ `shouldBe` Right (toByteStringS . Prelude.map toEnum . Prelude.take 43520 . Prelude.repeat $ 0x01) context "when encoding RLP structures" $ do it "should encode RLP structures with less than 56 bytes and one element" $ do (DBSL.unpack . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" ]) `shouldBe` [ 0xc1, 0x00 ] it "should decode it back" $ do- (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL [ RLPB . toByteStringS $ "\NUL" ])+ (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" ] :: ESR)+ `shouldBe` Right (RLPL [ RLPB . toByteStringS $ "\NUL" ]) it "should encode RLP structures with less than 56 bytes and more than one element" $ do (DBSL.unpack . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS $ "\NUL" ] ]) `shouldBe` [ 0xc3, 0x00, 0xc1, 0x00 ] it "should decode it back" $ do- (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS $ "\NUL" ] ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS $ "\NUL" ] ])+ (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS $ "\NUL" ] ] :: ESR)+ `shouldBe` Right (RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS $ "\NUL" ] ]) it "should encode RLP structures with more than 56 bytes and one element" $ do (DBSL.unpack . rlpEncode $ RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ]) `shouldBe` ([ 0xf8, 0x3e, 0xb8, 0x3c ] ++ (Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 0x01)) it "should decode it back" $ do- (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ])+ (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] :: ESR)+ `shouldBe` Right (RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ]) it "should encode RLP structures with more than 56 bytes and more than one element" $ do (DBSL.unpack . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] ]) `shouldBe` ([ 0xf8, 0x41, 0x00, 0xf8, 0x3e, 0xb8, 0x3c ] ++ (Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 0x01)) it "should decode it back" $ do- (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] ])+ (rlpDecode . rlpEncode $ RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] ] :: ESR)+ `shouldBe` Right (RLPL [ RLPB . toByteStringS $ "\NUL" , RLPL [ RLPB . toByteStringS . Prelude.map toEnum . Prelude.take 60 . Prelude.repeat $ 1 ] ]) context "when running Ethereum examples" $ do@@ -104,28 +107,28 @@ (DBSL.unpack . rlpEncode . toByteStringS $ "dog") `shouldBe` [ 0x83, 0x64, 0x6f, 0x67 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "dog" :: Maybe DBS.ByteString) `shouldBe` (Just $ toByteStringS "dog")+ (rlpDecode . rlpEncode . toByteStringS $ "dog" :: ESB) `shouldBe` Right (toByteStringS "dog") it "should encode [ cat, dog ]" $ do (DBSL.unpack . rlpEncode . RLPL . Prelude.map (RLPB . toByteStringS) $ [ "cat", "dog" ]) `shouldBe` [ 0xc8, 0x83, 0x63, 0x61, 0x74, 0x83, 0x64, 0x6f, 0x67 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . RLPL . Prelude.map (RLPB . toByteStringS) $ [ "cat", "dog" ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL . Prelude.map (RLPB . toByteStringS) $ [ "cat", "dog" ])+ (rlpDecode . rlpEncode . RLPL . Prelude.map (RLPB . toByteStringS) $ [ "cat", "dog" ] :: ESR)+ `shouldBe` Right (RLPL . Prelude.map (RLPB . toByteStringS) $ [ "cat", "dog" ]) it "should encode the set theoretical representation" $ do (DBSL.unpack . rlpEncode . toRLP $ RLPL [ RLPL [] , RLPL [ RLPL [] ] , RLPL [ RLPL [] , RLPL [ RLPL [] ] ] ]) `shouldBe` [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toRLP $ RLPL [ RLPL [] , RLPL [ RLPL [] ] , RLPL [ RLPL [] , RLPL [ RLPL [] ] ] ] :: Maybe RLPT)- `shouldBe` (Just $ RLPL [ RLPL [] , RLPL [ RLPL [] ] , RLPL [ RLPL [] , RLPL [ RLPL [] ] ] ])+ (rlpDecode . rlpEncode . toRLP $ RLPL [ RLPL [] , RLPL [ RLPL [] ] , RLPL [ RLPL [] , RLPL [ RLPL [] ] ] ] :: ESR)+ `shouldBe` Right (RLPL [ RLPL [] , RLPL [ RLPL [] ] , RLPL [ RLPL [] , RLPL [ RLPL [] ] ] ]) it "should encode LOREM IPSUM" $ do (DBSL.unpack . rlpEncode . toByteStringS $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit") `shouldBe` [ 0xb8, 0x38, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x69, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74 ] it "should decode it back" $ do- (rlpDecode . rlpEncode . toByteStringS $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit" :: Maybe DBS.ByteString)- `shouldBe` (Just $ toByteStringS $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit")+ (rlpDecode . rlpEncode . toByteStringS $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit" :: ESB)+ `shouldBe` Right (toByteStringS $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit")