argo-0.2021.11.11: source/library/Argo/Type/Decoder.hs
module Argo.Type.Decoder where
import qualified Argo.Literal as Literal
import qualified Argo.Vendor.ByteString as ByteString
import qualified Argo.Vendor.Transformers as Trans
import qualified Control.Applicative as Applicative
import qualified Control.Monad as Monad
import qualified Data.Functor.Identity as Identity
import qualified Data.Word as Word
type Decoder
= Trans.StateT
ByteString.ByteString
(Trans.ExceptT String Identity.Identity)
unwrap
:: Decoder a
-> ByteString.ByteString
-> Either String (a, ByteString.ByteString)
unwrap d = Identity.runIdentity . Trans.runExceptT . Trans.runStateT d
run :: Decoder a -> ByteString.ByteString -> Either String a
run d = fmap fst . unwrap (d <* eof)
list :: Decoder a -> Decoder [a]
list f = listWith f []
listWith :: Decoder a -> [a] -> Decoder [a]
listWith f xs = do
m <- Applicative.optional $ do
Monad.unless (null xs) $ do
word8 Literal.comma
spaces
f
case m of
Nothing -> pure $ reverse xs
Just x -> listWith f $ x : xs
byteString :: ByteString.ByteString -> Decoder ()
byteString x = do
b1 <- Trans.get
case ByteString.stripPrefix x b1 of
Nothing -> Trans.lift . Trans.throwE $ "byteString: " <> show x
Just b2 -> Trans.put b2
dropWhile :: (Word.Word8 -> Bool) -> Decoder ()
dropWhile f = do
b <- Trans.get
Trans.put $ ByteString.dropWhile f b
eof :: Decoder ()
eof = do
b <- Trans.get
Monad.unless (ByteString.null b) . Trans.lift $ Trans.throwE "eof"
isDigit :: Word.Word8 -> Bool
isDigit x = Literal.digitZero <= x && x <= Literal.digitNine
isSpace :: Word.Word8 -> Bool
isSpace x =
(x == Literal.space)
|| (x == Literal.horizontalTabulation)
|| (x == Literal.newLine)
|| (x == Literal.carriageReturn)
satisfy :: (Word.Word8 -> Bool) -> Decoder Word.Word8
satisfy f = do
b1 <- Trans.get
case ByteString.uncons b1 of
Just (x, b2) | f x -> do
Trans.put b2
pure x
_ -> Trans.lift $ Trans.throwE "satisfy"
spaces :: Decoder ()
spaces = Argo.Type.Decoder.dropWhile isSpace
takeWhile :: (Word.Word8 -> Bool) -> Decoder ByteString.ByteString
takeWhile f = do
b1 <- Trans.get
let (x, b2) = ByteString.span f b1
Trans.put b2
pure x
takeWhile1 :: (Word.Word8 -> Bool) -> Decoder ByteString.ByteString
takeWhile1 f = do
x <- Argo.Type.Decoder.takeWhile f
Monad.when (ByteString.null x) . Trans.lift $ Trans.throwE "takeWhile1"
pure x
word8 :: Word.Word8 -> Decoder ()
word8 = Monad.void . satisfy . (==)