ekmett / bytes

Serialization primitives that work with both cereal and binary.
http://hackage.haskell.org/package/bytes
Other
22 stars 13 forks source link

ExceptT instances for both MonadGet and MonadPut #20

Closed sw17ch closed 10 years ago

sw17ch commented 10 years ago

This patch adds ExceptT instances for MonadGet and MonadPut to Data.Bytes. From what I can tell, ExcepT is the successor to ErrorT.

Notes

I, being a little unsure of my Monad Transformers skill level opted to build a small file to test my implementation. The body is as follows:

module Main (main) where

import Data.Bytes.Put
import Control.Monad.Except
import Control.Monad.Trans.Except
import Data.Word
import qualified Data.ByteString as B

import qualified Data.Serialize.Put as S
import qualified Data.Serialize.Get as S

s :: B.ByteString
s = B.pack [100,200]

p :: S.PutM (Either String ()) -> IO ()
p a = case S.runPutM a of
        (Left e, r) -> putStrLn $ "Failure: " ++ e ++ " (" ++ show r ++ ")"
        (Right v, r) -> putStrLn $ "Success: " ++ show r ++ " (" ++ show v ++ ")"

g :: Show a => B.ByteString -> S.Get (Either String a) -> IO ()
g b a = print $ S.runGet a b

main :: IO ()
main = do
  putStrLn "Pack a 10."
  p $ runExceptT $ lift $ putWord8 10
  putStrLn ""

  putStrLn "Pack a 10 then fail."
  p $ runExceptT $ (lift $ putWord8 10) >> throwE "ugh"
  putStrLn ""

  putStrLn "lookAheadM and fail then lookAheadM and succeed"
  g s $ runExceptT $ do
    _ <- lift $ S.lookAheadM (return Nothing :: S.Get (Maybe Word8))
    lift $ S.lookAheadM (liftM Just S.getWord8 :: S.Get (Maybe Word8))
  putStrLn ""

  putStrLn "lookAheadE and fail then lookAheadM and succeed"
  g s $ runExceptT $ do
    e <- lift $ S.lookAheadE (return (Left "no") :: S.Get (Either String Word8))
    w <- lift $ S.lookAheadE (liftM Right S.getWord8 :: S.Get (Either String Word8))
    return (e,w)
  putStrLn ""

The output of this simple program for me is as follows:

Pack a 10.
Success: "\n" (())

Pack a 10 then fail.
Failure: ugh ("\n")

lookAheadM and fail then lookAheadM and succeed
Right (Right (Just 100))

lookAheadE and fail then lookAheadM and succeed
Right (Right (Left "no",Right 100))

The extra Either wrappers in the lookAheadM and lookAheadE examples are artifacts of Data.Serialize.Get.Get.

I hope I've implemented this correctly. Thanks for your earlier guidance that sent me down this path.

sw17ch commented 10 years ago

I altered bytes.cabal to depend on transformers-compat >= 0.3 rather than pushing up the transformers dependency.