Haskell signed binary data processing without unsafeCoerce

I read in the structure from a binary file that contains signed 16-bit integers using the Get monad from Data.Binary . My current code is as follows:

data DetectorStats = DetectorStats Int16 Word8 Word8 Word8 Int16 Version Int16 deriving Show getDetectorStats :: Get DetectorStats getDetectorStats = do productNumber <- getWord16be bitPerCoordinate <- getWord8 energyCapability <- getWord8 timingCapability <- getWord8 clockFrequency <- getWord16be serialNumber <- getWord16be return (DetectorStats (unsafeCoerce productNumber ) bitPerCoordinate energyCapability timingCapability (unsafeCoerce clockFrequency) firmwareVersion (unsafeCoerce serialNumber)) 

I am not happy with using unsafeCoerce , but there seems to be no way to read Int16 directly, nor is there a way to convert Word16 to Int16 . Is there a better way to handle this?

+8
binary haskell
source share
3 answers

fromIntegral converts Word16 to Int16. However, you must verify that it receives the result that you expect from signing.

+8
source share

The Data.Convertible package should do what you ask for.

For example, to convert from Word16 to Int16 :

 > (convert (6 :: Word16)) :: Int16 6 
+3
source share

Based on Stephen’s answer, an implementation of get and put functions for Int8, Int16, and Int32, similar to those for Word8, Word16, and Word32, is presented here. I don't need Int64 or host endian support yet, but they can be added:

 {-# LANGUAGE RecordWildCards #-} module GetAndPutForInt ( getInt8 , getInt16be , getInt16le , getInt32be , getInt32le , putInt8 , putInt16be , putInt16le , putInt32be , putInt32le ) where import Data.Binary import Data.Binary.Get import Data.Binary.Put import Data.Int import Data.Word import qualified Data.ByteString.Lazy as B getInt8 :: Get Int8 getInt8 = do a <- getWord8 return $ fromIntegral a getInt16be :: Get Int16 getInt16be = do a <- getWord16be return $ fromIntegral a getInt16le :: Get Int16 getInt16le = do a <- getWord16le return $ fromIntegral a getInt32be :: Get Int32 getInt32be = do a <- getWord32be return $ fromIntegral a getInt32le :: Get Int32 getInt32le = do a <- getWord32le return $ fromIntegral a putInt8 :: Int8 -> Put putInt8 i = putWord8 ((fromIntegral i) :: Word8) putInt16be :: Int16 -> Put putInt16be i = putWord16be ((fromIntegral i) :: Word16) putInt16le :: Int16 -> Put putInt16le i = putWord16le ((fromIntegral i) :: Word16) putInt32be :: Int32 -> Put putInt32be i = putWord32be ((fromIntegral i) :: Word32) putInt32le :: Int32 -> Put putInt32le i = putWord32le ((fromIntegral i) :: Word32) data TestType = TestType { a :: Int16 , b :: Int16 } deriving (Show, Eq) instance Binary TestType where put TestType{..} = do putInt16be a putInt16le b get = do a <- getInt16be b <- getInt16le return TestType{..} main :: IO () main = do putStrLn "Supplies Get and Put support to Int8, Int16 etc. types as Data.Binary.Get and Data.Binary.Push do for Word8, Word 16 etc." putStrLn "" putStrLn "Test data in bytes:" print bytes putStrLn "" putStrLn "As TestType:" print (decode bytes :: TestType) putStrLn "" putStrLn "Back to bytes:" print $ (encode ((decode bytes) :: TestType)) where bytes = B.pack $ concat $ replicate 2 [0xCD,0xEF] 
+1
source share

All Articles