module VLQ
(encode
,decode)
where
import Data.Bits hiding (shift)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import Data.Int
import Data.List
import Data.Maybe
import Data.Word
import Prelude hiding ((>>))
baseShift :: Int
baseShift :: Int
baseShift = Int
5
base :: Int32
base :: Int32
base = Int32
1 Int32 -> Int -> Int32
<< Int
baseShift
baseMask :: Int32
baseMask :: Int32
baseMask = Int32
base forall a. Num a => a -> a -> a
- Int32
1
continuationBit :: Int32
continuationBit :: Int32
continuationBit = Int32
base
toVlqSigned :: Int32 -> Int32
toVlqSigned :: Int32 -> Int32
toVlqSigned Int32
value =
if Int32
value forall a. Ord a => a -> a -> Bool
< Int32
0
then ((-Int32
value) Int32 -> Int -> Int32
<< Int
1) forall a. Num a => a -> a -> a
+ Int32
1
else (Int32
value Int32 -> Int -> Int32
<< Int
1) forall a. Num a => a -> a -> a
+ Int32
0
fromVlgSigned :: Int32 -> Int32
fromVlgSigned :: Int32 -> Int32
fromVlgSigned Int32
value =
let value' :: Int32
value' = Int32
value Int32 -> Int -> Int32
>> Int
1
in if (Int32
value Int32 -> Int32 -> Int32
& Int32
1) forall a. Eq a => a -> a -> Bool
== Int32
1
then -Int32
value'
else Int32
value'
encode :: Int32 -> ByteString
encode :: Int32 -> ByteString
encode = (Word8 -> Word8) -> ByteString -> ByteString
B.map Word8 -> Word8
encodeBase64 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> ByteString
start where
start :: Int32 -> ByteString
start Int32
0 = Word8 -> ByteString
B.singleton (forall a b. (a, b) -> a
fst (forall {a}. Num a => Int32 -> (a, Int32)
continue Int32
0))
start Int32
n = forall a. (a -> Maybe (Word8, a)) -> a -> ByteString
B.unfoldr forall {a}. Num a => Int32 -> Maybe (a, Int32)
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> Int32
toVlqSigned forall a b. (a -> b) -> a -> b
$ Int32
n
go :: Int32 -> Maybe (a, Int32)
go Int32
value
| Int32
value forall a. Ord a => a -> a -> Bool
<= Int32
0 = forall a. Maybe a
Nothing
| Bool
otherwise = forall a. a -> Maybe a
Just (forall {a}. Num a => Int32 -> (a, Int32)
continue Int32
value)
continue :: Int32 -> (a, Int32)
continue Int32
value =
let digit :: Int32
digit = Int32
value Int32 -> Int32 -> Int32
& Int32
baseMask
value' :: Int32
value' = Int32
value Int32 -> Int -> Int32
>> Int
baseShift
digit' :: Int32
digit' = if Int32
value' forall a. Ord a => a -> a -> Bool
> Int32
0
then Int32
digit forall a. Bits a => a -> a -> a
.|. Int32
continuationBit
else Int32
digit
in (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
digit',Int32
value')
decode :: ByteString -> Int32
decode :: ByteString -> Int32
decode = Int32 -> Int32
fromVlgSigned forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int32, Int) -> ByteString -> Int32
go (Int32
0,Int
0) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Word8) -> ByteString -> ByteString
B.map Word8 -> Word8
decodeBase64 where
go :: (Int32, Int) -> ByteString -> Int32
go (Int32
result,Int
shift) ByteString
bytes =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
bytes of
Maybe (Word8, ByteString)
Nothing -> Int32
result
Just (Word8
c,ByteString
next) ->
let digit :: Int32
digit = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
c
continuation :: Bool
continuation = (Int32
digit Int32 -> Int32 -> Int32
& Int32
continuationBit) forall a. Eq a => a -> a -> Bool
/= Int32
0
digit' :: Int32
digit' = Int32
digit Int32 -> Int32 -> Int32
& Int32
baseMask
result' :: Int32
result' = Int32
result forall a. Num a => a -> a -> a
+ (Int32
digit' Int32 -> Int -> Int32
<< Int
shift)
shift' :: Int
shift' = Int
shift forall a. Num a => a -> a -> a
+ Int
baseShift
in if Bool
continuation
then (Int32, Int) -> ByteString -> Int32
go (Int32
result',Int
shift') ByteString
next
else Int32
result'
base64Chars :: [Word8]
base64Chars :: [Word8]
base64Chars = forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (Integral a, Num b) => a -> b
fromIntegralforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a. Enum a => a -> Int
fromEnum) String
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
encodeBase64 :: Word8 -> Word8
encodeBase64 :: Word8 -> Word8
encodeBase64 Word8
i = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"Base 64 char must be between 0 and 63.")
(forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Word8
i (forall a b. [a] -> [b] -> [(a, b)]
zip [Word8
0..] [Word8]
base64Chars))
decodeBase64 :: Word8 -> Word8
decodeBase64 :: Word8 -> Word8
decodeBase64 Word8
i = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a. HasCallStack => String -> a
error String
"Not a valid base 65 digit.") forall a. Enum a => Int -> a
toEnum
(forall a. Eq a => a -> [a] -> Maybe Int
elemIndex Word8
i [Word8]
base64Chars)
(<<) :: Int32 -> Int -> Int32
<< :: Int32 -> Int -> Int32
(<<) = forall a. Bits a => a -> Int -> a
shiftL
(>>) :: Int32 -> Int -> Int32
>> :: Int32 -> Int -> Int32
(>>) = forall a. Bits a => a -> Int -> a
shiftR
(&) :: Int32 -> Int32 -> Int32
& :: Int32 -> Int32 -> Int32
(&) = forall a. Bits a => a -> a -> a
(.&.)