module BinaryParser
(
BinaryParser,
run,
failure,
byte,
bytesOfSize,
unitOfSize,
unitOfBytes,
remainders,
endOfInput,
sized,
)
where
import BinaryParser.Prelude
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Unsafe as ByteString
import qualified Success.Pure as Success
newtype BinaryParser a =
BinaryParser ( StateT ByteString ( Success.Success Text ) a )
deriving ( Functor , Applicative , Alternative , Monad , MonadPlus )
run :: BinaryParser a -> ByteString -> Either Text a
run (BinaryParser parser) input =
mapLeft fold (Success.asEither (evalStateT parser input))
failure :: Text -> BinaryParser a
failure text =
BinaryParser (lift (Success.failure text))
byte :: BinaryParser Word8
byte =
BinaryParser $ StateT $ \remainders ->
if ByteString.null remainders
then Success.failure "End of input"
else pure (ByteString.unsafeHead remainders, ByteString.unsafeDrop 1 remainders)
bytesOfSize :: Int -> BinaryParser ByteString
bytesOfSize size =
BinaryParser $ StateT $ \remainders ->
if ByteString.length remainders >= size
then return (ByteString.unsafeTake size remainders, ByteString.unsafeDrop size remainders)
else Success.failure "End of input"
unitOfSize :: Int -> BinaryParser ()
unitOfSize size =
BinaryParser $ StateT $ \remainders ->
if ByteString.length remainders >= size
then return ((), ByteString.unsafeDrop size remainders)
else Success.failure "End of input"
unitOfBytes :: ByteString -> BinaryParser ()
unitOfBytes bytes =
BinaryParser $ StateT $ \remainders ->
if ByteString.isPrefixOf bytes remainders
then return ((), ByteString.unsafeDrop (ByteString.length bytes) remainders)
else Success.failure "Bytes don't match"
remainders :: BinaryParser ByteString
remainders =
BinaryParser $ StateT $ \remainders -> return (remainders, ByteString.empty)
endOfInput :: BinaryParser ()
endOfInput =
BinaryParser $ StateT $ \case
"" -> return ((), ByteString.empty)
_ -> Success.failure "Not the end of input"
sized :: Int -> BinaryParser a -> BinaryParser a
sized size (BinaryParser stateT) =
BinaryParser $ StateT $ \remainders ->
if ByteString.length remainders >= size
then
evalStateT stateT (ByteString.unsafeTake size remainders) &
fmap (\result -> (result, ByteString.unsafeDrop size remainders))
else Success.failure "End of input"