fir-0.1.0.0: src/Data/Binary/Class/Put.hs
{-# LANGUAGE TypeApplications #-}
{-|
Module: Data.Binary.Class.Put
One half of the 'Data.Binary.Binary' type class: putting.
This type class is used to provide arguments to @SPIR-V@
instructions; everything comes in multiples of 'Word32'.
The instances provided in this module are /little endian/,
in agreement with the default endianness for @SPIR-V@ assembly.
Note: this type class is __not__ concerned with memory layout on the GPU.
GPU memory layout is managed using @SPIR-V@ decorations, in conjunction with @Vulkan@.
This type class is instead used internally, to emit binary SPIR-V assembly.
-}
module Data.Binary.Class.Put
(
-- * Put type class
Put(..)
-- ** Instances
-- $instances
, PutWord32Enum(..)
) where
-- base
import Data.Coerce
( coerce )
import Data.Int
( Int8,Int16,Int32,Int64 )
import Data.Semigroup
( stimes )
import Data.Word
( Word8,Word16,Word32,Word64 )
import Foreign.C.Types
( CUShort(CUShort) )
-- binary
import qualified Data.Binary.Put as Binary
( PutM
, putWord8, putWord16le
, putWord32le, putWord64le
, putInt32le, putInt64le
, putFloatle, putDoublele
, putShortByteString
)
-- bytestring
import qualified Data.ByteString.Short as ShortByteString
( length )
-- half
import Numeric.Half
( Half(Half) )
-- text-short
import Data.Text.Short
( ShortText )
import qualified Data.Text.Short as ShortText
( toShortByteString )
----------------------------------------------------------------------------
-- Put type class
-- | One half of 'Data.Binary.Binary'.
class Put a where
put :: a -> Binary.PutM ()
-- | Memory footprint, as a multiple of __32 bits__
-- (/not/ the usual 8 bits as in 'Foreign.Storable.sizeOf').
wordCount :: a -> Word32
---------------------------------------------------------------------------
-- $instances
--
-- Little-endian instances are provided for 'Put',
-- as these are best suited to @SPIR-V@.
--
-- Note that types smaller than 32 bits are immediately padded:
-- this type class is purely used for specifying arguments
-- to @SPIR-V@ instructions, and the smallest allowed size is 32 bits;
-- it is not possible to tightly pack arguments of smaller sizes.
instance Put Word8 where
put = Binary.putWord32le . fromIntegral
wordCount _ = 1
instance Put Word16 where
put = Binary.putWord32le . fromIntegral
wordCount _ = 1
instance Put Word32 where
put = Binary.putWord32le
wordCount _ = 1
instance Put Word64 where
put = Binary.putWord64le
wordCount _ = 2
instance Put Int8 where
put = Binary.putInt32le . fromIntegral
wordCount _ = 1
instance Put Int16 where
put = Binary.putInt32le . fromIntegral
wordCount _ = 1
instance Put Int32 where
put = Binary.putInt32le
wordCount _ = 1
instance Put Int64 where
put = Binary.putInt64le
wordCount _ = 2
instance Put Half where
put h = do
Binary.putWord16le (coerce h)
Binary.putWord16le 0
wordCount _ = 1
instance Put Float where
put = Binary.putFloatle
wordCount _ = 1
instance Put Double where
put = Binary.putDoublele
wordCount _ = 2
-- | @C@-style string
instance Put ShortText where
put lit =
let n = ShortByteString.length (ShortText.toShortByteString lit)
pad = 4 - (n `mod` 4)
in Binary.putShortByteString (ShortText.toShortByteString lit)
<> (pad `stimes` Binary.putWord8 0)
wordCount lit
= let n = fromIntegral $ ShortByteString.length (ShortText.toShortByteString lit)
in 1 + (n `div` 4)
----------------------------------------------------------------------------
-- | Newtype for 'Put' instance using 'Enum'.
--
-- Useful with deriving via:
-- @ data ... deriving Put via (PutWord32Enum ...) @.
newtype PutWord32Enum a = PutWord32Enum { runPutWord32Enum :: a }
instance Enum a => Put (PutWord32Enum a) where
put = put @Word32 . fromIntegral . fromEnum . runPutWord32Enum
wordCount _ = 1