simple-parser-0.8.0: src/SimpleParser/Chunked.hs
module SimpleParser.Chunked
( Chunked (..)
, TextualChunked (..)
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.Foldable (toList)
import Data.List (uncons)
import Data.Sequence (Seq (..))
import qualified Data.Sequence as Seq
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Word (Word8)
import Text.Builder (Builder)
import qualified Text.Builder as TB
-- | 'Chunked' captures the basic relationship between tokens and chunks of them.
-- Basically, these things behave like lists, sequences, text, etc.
class Monoid chunk => Chunked chunk token | chunk -> token where
consChunk :: token -> chunk -> chunk
unconsChunk :: chunk -> Maybe (token, chunk)
tokenToChunk :: token -> chunk
tokensToChunk :: [token] -> chunk
chunkToTokens :: chunk -> [token]
chunkLength :: chunk -> Int
chunkEmpty :: chunk -> Bool
-- | Some datatypes (like 'Seq') may admit a "better" implementation
-- for building a chunk in reverse.
revTokensToChunk :: [token] -> chunk
revTokensToChunk = tokensToChunk . reverse
-- | Captures textual streams.
class Chunked chunk Char => TextualChunked chunk where
buildChunk :: chunk -> Builder
buildChunk = TB.text . packChunk
packChunk :: chunk -> Text
packChunk = TB.run . buildChunk
unpackChunk :: Text -> chunk
{-# MINIMAL (buildChunk | packChunk), unpackChunk #-}
instance Chunked [a] a where
consChunk = (:)
unconsChunk = uncons
tokenToChunk a = [a]
tokensToChunk = id
chunkToTokens = id
chunkLength = length
chunkEmpty = null
instance (a ~ Char) => TextualChunked [a] where
buildChunk = TB.string
packChunk = T.pack
unpackChunk = T.unpack
instance Chunked (Seq a) a where
consChunk = (:<|)
unconsChunk s =
case s of
Empty -> Nothing
a :<| b -> Just (a, b)
tokenToChunk = Seq.singleton
tokensToChunk = Seq.fromList
chunkToTokens = toList
chunkLength = Seq.length
chunkEmpty = Seq.null
revTokensToChunk = foldr (flip (:|>)) Empty
instance (a ~ Char) => TextualChunked (Seq a) where
buildChunk = TB.string . toList
packChunk = T.pack . toList
unpackChunk = Seq.fromList . T.unpack
instance Chunked Text Char where
consChunk = T.cons
unconsChunk = T.uncons
tokenToChunk = T.singleton
tokensToChunk = T.pack
chunkToTokens = T.unpack
chunkLength = T.length
chunkEmpty = T.null
instance TextualChunked Text where
buildChunk = TB.text
packChunk = id
unpackChunk = id
instance Chunked TL.Text Char where
consChunk = TL.cons
unconsChunk = TL.uncons
tokenToChunk = TL.singleton
tokensToChunk = TL.pack
chunkToTokens = TL.unpack
chunkLength = fromIntegral . TL.length
chunkEmpty = TL.null
instance TextualChunked TL.Text where
buildChunk = TB.text . TL.toStrict
packChunk = TL.toStrict
unpackChunk = TL.fromStrict
instance Chunked ByteString Word8 where
consChunk = BS.cons
unconsChunk = BS.uncons
tokenToChunk = BS.singleton
tokensToChunk = BS.pack
chunkToTokens = BS.unpack
chunkLength = BS.length
chunkEmpty = BS.null
instance Chunked BSL.ByteString Word8 where
consChunk = BSL.cons
unconsChunk = BSL.uncons
tokenToChunk = BSL.singleton
tokensToChunk = BSL.pack
chunkToTokens = BSL.unpack
chunkLength = fromIntegral . BSL.length
chunkEmpty = BSL.null