winery-0.1: src/Data/Winery/Internal.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Winery.Internal
( Encoding(..)
, encodeMulti
, encodeVarInt
, Decoder
, decodeAt
, decodeVarInt
, Offsets
, decodeOffsets
, getWord8
, word16be
, word32be
, word64be
, unsafeIndex
, unsafeIndexV
, Strategy(..)
, StrategyError
, errorStrategy
, TransList(..)
, TransFusion(..)
, runTransFusion
)where
import Control.Applicative
import Control.Monad
import Control.Monad.Fix
import Control.Monad.ST
import Control.Monad.Trans.Cont
import Data.ByteString.FastBuilder
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import qualified Data.ByteString.FastBuilder as BB
import Data.Bits
import Data.Dynamic
import Data.Monoid
import Data.Text.Prettyprint.Doc (Doc)
import Data.Text.Prettyprint.Doc.Render.Terminal (AnsiStyle)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as UM
import Data.Word
data Encoding = Encoding
{ encodingLength :: !Int, encodingBuilder :: !Builder }
instance Monoid Encoding where
mempty = Encoding 0 mempty
mappend (Encoding m a) (Encoding n b) = Encoding (m + n) (mappend a b)
rebuildEncoding :: Encoding -> Encoding
rebuildEncoding (Encoding l b) = Encoding l (BB.rebuild b)
type Decoder = (->) B.ByteString
decodeAt :: (Int, Int) -> Decoder a -> Decoder a
decodeAt (i, l) m bs = m $ B.take l $ B.drop i bs
encodeVarInt :: (Bits a, Integral a) => a -> Encoding
encodeVarInt n
| n < 0 = case negate n of
n'
| n' < 0x40 -> e1 (fromIntegral n' `setBit` 6)
| otherwise -> go (e1 (0xc0 .|. fromIntegral n')) (shiftR n' 6)
| n < 0x40 = e1 (fromIntegral n)
| otherwise = go (e1 (fromIntegral n `setBit` 7 `clearBit` 6)) (shiftR n 6)
where
e1 = Encoding 1 . BB.word8
go !acc m
| m < 0x80 = acc `mappend` e1 (fromIntegral m)
| otherwise = go (acc <> e1 (setBit (fromIntegral m) 7)) (shiftR m 7)
{-# INLINE encodeVarInt #-}
getWord8 :: ContT r Decoder Word8
getWord8 = ContT $ \k bs -> case B.uncons bs of
Nothing -> k 0 bs
Just (x, bs') -> k x $! bs'
{-# INLINE getWord8 #-}
decodeVarInt :: (Num a, Bits a) => ContT r Decoder a
decodeVarInt = getWord8 >>= \case
n | testBit n 7 -> do
m <- getWord8 >>= go
if testBit n 6
then return $! negate $ shiftL m 6 .|. fromIntegral n .&. 0x3f
else return $! shiftL m 6 .|. clearBit (fromIntegral n) 7
| testBit n 6 -> return $ negate $ fromIntegral $ clearBit n 6
| otherwise -> return $ fromIntegral n
where
go n
| testBit n 7 = do
m <- getWord8 >>= go
return $! shiftL m 7 .|. clearBit (fromIntegral n) 7
| otherwise = return $ fromIntegral n
{-# INLINE decodeVarInt #-}
word16be :: B.ByteString -> Word16
word16be = \s -> if B.length s >= 2
then
(fromIntegral (s `B.unsafeIndex` 0) `unsafeShiftL` 8) .|.
(fromIntegral (s `B.unsafeIndex` 1))
else error "word16be"
word32be :: B.ByteString -> Word32
word32be = \s -> if B.length s >= 4
then
(fromIntegral (s `B.unsafeIndex` 0) `unsafeShiftL` 24) .|.
(fromIntegral (s `B.unsafeIndex` 1) `unsafeShiftL` 16) .|.
(fromIntegral (s `B.unsafeIndex` 2) `unsafeShiftL` 8) .|.
(fromIntegral (s `B.unsafeIndex` 3) )
else error "word32be"
word64be :: B.ByteString -> Word64
word64be = \s -> if B.length s >= 8
then
(fromIntegral (s `B.unsafeIndex` 0) `unsafeShiftL` 56) .|.
(fromIntegral (s `B.unsafeIndex` 1) `unsafeShiftL` 48) .|.
(fromIntegral (s `B.unsafeIndex` 2) `unsafeShiftL` 40) .|.
(fromIntegral (s `B.unsafeIndex` 3) `unsafeShiftL` 32) .|.
(fromIntegral (s `B.unsafeIndex` 4) `unsafeShiftL` 24) .|.
(fromIntegral (s `B.unsafeIndex` 5) `unsafeShiftL` 16) .|.
(fromIntegral (s `B.unsafeIndex` 6) `unsafeShiftL` 8) .|.
(fromIntegral (s `B.unsafeIndex` 7) )
else error $ "word64be" ++ show s
encodeMulti :: [Encoding] -> Encoding
encodeMulti xs = rebuildEncoding
$ foldMap (encodeVarInt . encodingLength) (safeInit xs) <> mconcat xs
where
safeInit [] = []
safeInit [_] = []
safeInit (y:ys) = y : safeInit ys
{-# INLINE encodeMulti #-}
type Offsets = U.Vector (Int, Int)
decodeOffsets :: Int -> ContT r Decoder Offsets
decodeOffsets 0 = pure U.empty
decodeOffsets n = accum <$> U.replicateM (n - 1) decodeVarInt where
accum xs = runST $ do
r <- UM.unsafeNew (U.length xs + 1)
let go s i
| i == U.length xs = do
UM.write r i (s, maxBound)
U.unsafeFreeze r
| otherwise = do
let x = U.unsafeIndex xs i
let s' = s + x
UM.write r i (s, x)
go s' (i + 1)
go 0 0
unsafeIndexV :: U.Unbox a => String -> U.Vector a -> Int -> a
unsafeIndexV err xs i
| i >= U.length xs || i < 0 = error err
| otherwise = U.unsafeIndex xs i
{-# INLINE unsafeIndexV #-}
unsafeIndex :: String -> [a] -> Int -> a
unsafeIndex err xs i = (xs ++ repeat (error err)) !! i
type StrategyError = Doc AnsiStyle
newtype Strategy a = Strategy { unStrategy :: [Decoder Dynamic] -> Either StrategyError a }
deriving Functor
instance Applicative Strategy where
pure = return
(<*>) = ap
instance Monad Strategy where
return = Strategy . const . Right
m >>= k = Strategy $ \decs -> case unStrategy m decs of
Right a -> unStrategy (k a) decs
Left e -> Left e
instance Alternative Strategy where
empty = Strategy $ const $ Left "empty"
Strategy a <|> Strategy b = Strategy $ \decs -> case a decs of
Left _ -> b decs
Right x -> Right x
instance MonadFix Strategy where
mfix f = Strategy $ \r -> mfix $ \a -> unStrategy (f a) r
{-# INLINE mfix #-}
errorStrategy :: Doc AnsiStyle -> Strategy a
errorStrategy = Strategy . const . Left
newtype TransFusion f g a = TransFusion { unTransFusion :: forall h. Applicative h => (forall x. f x -> h (g x)) -> h a }
runTransFusion :: TransFusion f g a -> TransList f g a
runTransFusion (TransFusion k) = k (\f -> More f (Done id))
instance Functor (TransFusion f g) where
fmap f (TransFusion m) = TransFusion $ \k -> fmap f (m k)
{-# INLINE fmap #-}
instance Applicative (TransFusion f g) where
pure a = TransFusion $ \_ -> pure a
TransFusion a <*> TransFusion b = TransFusion $ \k -> a k <*> b k
{-# INLINE (<*>) #-}
data TransList f g a = Done a | forall x. More (f x) (TransList f g (g x -> a))
deriving instance Functor (TransList f g)
instance Applicative (TransList f g) where
pure = Done
Done f <*> a = fmap f a
More i k <*> c = More i (flip <$> k <*> c)