{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleInstances #-}
module Codec.LEB128.Internal.BS
( fromULEB128
, fromSLEB128
, fromULEB128Unsafe
, fromSLEB128Unsafe
, toULEB128
, toSLEB128
)
where
import Data.Word (Word8)
import Data.Maybe
import GHC.Magic
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString as BS
import Control.Monad.Trans.State.Strict
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Class
import Control.Monad
import Codec.LEB128.Constraints
import Codec.LEB128.Generic as G
{-# INLINEABLE toULEB128 #-}
toULEB128 :: LEB128 a => a -> B.Builder
toULEB128 = (inline G.encodeLEB128) (B.word8)
{-# INLINEABLE toSLEB128 #-}
toSLEB128 :: SLEB128 a => a -> B.Builder
toSLEB128 = (inline G.encodeSLEB128) (B.word8)
type UnsafeByteProvider = State (BS.ByteString)
{-# INLINABLE getByteUnsafe #-}
getByteUnsafe :: UnsafeByteProvider Word8
getByteUnsafe = do
(bs) <- get
let (!byte,!bs') = fromMaybe (error "Not enough bytes") $ BS.uncons bs
put $! bs'
return byte
{-# INLINABLE fromULEB128Unsafe #-}
fromULEB128Unsafe :: LEB128 a => BS.ByteString -> (a,BS.ByteString)
fromULEB128Unsafe bytes = runState
((inline G.decodeLEB128) getByteUnsafe)
bytes
{-# INLINABLE fromSLEB128Unsafe #-}
fromSLEB128Unsafe :: SLEB128 a => BS.ByteString -> (a,BS.ByteString)
fromSLEB128Unsafe bytes = runState
((inline G.decodeSLEB128) getByteUnsafe)
bytes
type ByteProvider a = MaybeT (State BS.ByteString) a
{-# INLINE runByteProvider #-}
runByteProvider :: ByteProvider a -> BS.ByteString -> (Maybe a, BS.ByteString)
runByteProvider action = runState (runMaybeT action)
{-# INLINE liftMaybe #-}
liftMaybe :: (MonadPlus m) => Maybe a -> m a
liftMaybe = maybe mzero return
{-# INLINABLE getByte #-}
getByte :: (ByteProvider Word8)
getByte = do
(bs) <- lift get
(!byte,!bs') <- liftMaybe (BS.uncons bs)
lift $! put $! bs'
return byte
{-# INLINABLE fromULEB128 #-}
fromULEB128 :: forall a. LEB128 a => BS.ByteString -> (Maybe a,BS.ByteString)
fromULEB128 =
let decode = (inline G.decodeLEB128) getByte :: MaybeT (State BS.ByteString) a
in runByteProvider decode
{-# INLINABLE fromSLEB128 #-}
fromSLEB128 :: forall a. SLEB128 a => BS.ByteString -> (Maybe a,BS.ByteString)
fromSLEB128 =
let decode = (inline G.decodeSLEB128) getByte :: MaybeT (State BS.ByteString) a
in runByteProvider decode