-- |
-- Module:      Data.ProtoBuf.ZigZag
-- Copyright:   (c) 2015-2016 Martijn Rijkeboer <mrr@sru-systems.com>
-- License:     MIT
-- Maintainer:  Martijn Rijkeboer <mrr@sru-systems.com>
--
-- Functions to ZigZag encode and decode Int32 and Int64.

module Data.ProtoBuf.ZigZag
    ( decode32
    , decode64
    , encode32
    , encode64
    ) where

import Data.Bits ((.&.), shiftL, shiftR, xor)
import Data.Int (Int32, Int64)
import Data.Word (Word32, Word64)


-- | Decode a ZigZag encoded Int32.
decode32 :: Word32 -> Int32
decode32 :: Word32 -> Int32
decode32 Word32
x = Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
xor (Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Word32 -> Int32
forall a b. (a -> b) -> a -> b
$ Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftR Word32
x Int
1) (Int32 -> Int32
forall a. Num a => a -> a
negate (Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Word32 -> Int32
forall a b. (a -> b) -> a -> b
$ Word32
x Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
1))


-- | Decode a ZigZag encoded Int64.
decode64 :: Word64 -> Int64
decode64 :: Word64 -> Int64
decode64 Word64
x = Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
xor (Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int64) -> Word64 -> Int64
forall a b. (a -> b) -> a -> b
$ Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
shiftR Word64
x Int
1) (Int64 -> Int64
forall a. Num a => a -> a
negate (Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int64) -> Word64 -> Int64
forall a b. (a -> b) -> a -> b
$ Word64
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
1))


-- | ZigZag encode an Int32.
encode32 :: Int32 -> Word32
encode32 :: Int32 -> Word32
encode32 Int32
x = Int32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int32 -> Word32) -> Int32 -> Word32
forall a b. (a -> b) -> a -> b
$ Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
xor (Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftL Int32
x Int
1) (Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftR Int32
x Int
31)


-- | ZigZag encode an Int64.
encode64 :: Int64 -> Word64
encode64 :: Int64 -> Word64
encode64 Int64
x = Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Word64) -> Int64 -> Word64
forall a b. (a -> b) -> a -> b
$ Int64 -> Int64 -> Int64
forall a. Bits a => a -> a -> a
xor (Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
shiftL Int64
x Int
1) (Int64 -> Int -> Int64
forall a. Bits a => a -> Int -> a
shiftR Int64
x Int
63)