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