{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Trustworthy      #-}

-- | This module was written based on
--   <http://hackage.haskell.org/package/reinterpret-cast-0.1.0/docs/src/Data-ReinterpretCast-Internal-ImplArray.html>.
--
--   Implements casting via a 1-elemnt STUArray, as described in
--   <http://stackoverflow.com/a/7002812/263061>.
module Util.FloatCast
    ( floatToWord
    , wordToFloat
    , doubleToWord
    , wordToDouble
    ) where

import           Data.Word         ( Word32, Word64 )
import           Data.Array.ST     ( MArray, STUArray, newArray, readArray )
import           Data.Array.Unsafe ( castSTUArray )
import           GHC.ST            ( ST, runST )

-- | Reinterpret-casts a `Float` to a `Word32`.
floatToWord :: Float -> Word32
floatToWord x = runST (cast x)

{-# INLINE floatToWord #-}

-- | Reinterpret-casts a `Word32` to a `Float`.
wordToFloat :: Word32 -> Float
wordToFloat x = runST (cast x)

{-# INLINE wordToFloat #-}

-- | Reinterpret-casts a `Double` to a `Word64`.
doubleToWord :: Double -> Word64
doubleToWord x = runST (cast x)

{-# INLINE doubleToWord #-}

-- | Reinterpret-casts a `Word64` to a `Double`.
wordToDouble :: Word64 -> Double
wordToDouble x = runST (cast x)

{-# INLINE wordToDouble #-}

cast :: (MArray (STUArray s) a (ST s), MArray (STUArray s) b (ST s)) => a -> ST s b
cast x = newArray (0 :: Int, 0) x >>= castSTUArray >>= flip readArray 0

{-# INLINE cast #-}