--------------------------------------------------------------------
-- |
-- Module    : Data.Ruby.Marshal.Int
-- Copyright : (c) Philip Cunningham, 2015
-- License   : MIT
--
-- Maintainer:  hello@filib.io
-- Stability :  experimental
-- Portability: portable
--
-- Parsers for signed and unsigned integrals.
--
--------------------------------------------------------------------

module Data.Ruby.Marshal.Int (
  -- * Signed integrals
    getInt8
  , getInt16le
  , getInt24le
  , getInt32le
  , Int16
  -- * Unsigned integrals
  , getWord8
  , getWord16le
  , getWord24le
  , getWord32le
  , Word8
) where

import           Control.Applicative
import           Data.Bits           (shiftL, (.|.))
import qualified Data.ByteString     as BS
import           Data.Int            (Int16, Int32, Int8)
import           Data.Serialize.Get  (Get, getBytes, getWord16le, getWord32le,
                                      getWord8)
import           Data.Word           (Word32, Word8)
import           Prelude

-- | Read an Int8.
getInt8 :: Get Int8
getInt8 :: Get Int8
getInt8 = Word8 -> Int8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int8) -> Get Word8 -> Get Int8
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word8
getWord8

-- | Read an Int16.
getInt16le :: Get Int16
getInt16le :: Get Int16
getInt16le = Word16 -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int16) -> Get Word16 -> Get Int16
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word16
getWord16le

-- | Read a Word24 in little endian format. Since Word24 unavailable in Data.Int
-- we use Word32.
getWord24le :: Get Word32
getWord24le :: Get Word32
getWord24le = do
  ByteString
s <- Int -> Get ByteString
getBytes 3
  Word32 -> Get Word32
forall (m :: * -> *) a. Monad m => a -> m a
return (Word32 -> Get Word32) -> Word32 -> Get Word32
forall a b. (a -> b) -> a -> b
$! (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString
s ByteString -> Int -> Word8
`BS.index` 2) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftL` 16) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.
            (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString
s ByteString -> Int -> Word8
`BS.index` 1) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`shiftL` 8) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|.
             Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString
s ByteString -> Int -> Word8
`BS.index` 0)

-- | Read an Int24. Since Int24 unavailable in Data.Int we use Int32.
getInt24le :: Get Int32
getInt24le :: Get Int32
getInt24le = Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Get Word32 -> Get Int32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word32
getWord24le

-- | Read an Int32.
getInt32le :: Get Int32
getInt32le :: Get Int32
getInt32le = Word32 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int32) -> Get Word32 -> Get Int32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Word32
getWord32le