Skip to content

Commit 9389451

Browse files
aviethqnikst
authored andcommitted
Define decodeWord32, encodeWord32 (#34)
* Define decodeWord32, encodeWord32 From these concrete functions, the general Enum and Num varieties are derived. * Use Word32, Word16 over CInt, CShort
1 parent a59052e commit 9389451

File tree

1 file changed

+54
-34
lines changed

1 file changed

+54
-34
lines changed

src/Network/Transport/Internal.hs

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
-- | Internal functions
22
module Network.Transport.Internal
33
( -- * Encoders/decoders
4-
encodeInt32
5-
, decodeInt32
6-
, encodeInt16
7-
, decodeInt16
4+
encodeWord32
5+
, decodeWord32
6+
, encodeEnum32
7+
, decodeNum32
8+
, encodeWord16
9+
, decodeWord16
10+
, encodeEnum16
11+
, decodeNum16
812
, prependLength
913
-- * Miscellaneous abstractions
1014
, mapIOException
@@ -24,7 +28,6 @@ import Prelude hiding (catch)
2428
#endif
2529

2630
import Foreign.Storable (pokeByteOff, peekByteOff)
27-
import Foreign.C (CInt(..), CShort(..))
2831
import Foreign.ForeignPtr (withForeignPtr)
2932
import Data.ByteString (ByteString)
3033
import qualified Data.ByteString as BS (length)
@@ -33,6 +36,7 @@ import qualified Data.ByteString.Internal as BSI
3336
, toForeignPtr
3437
, inlinePerformIO
3538
)
39+
import Data.Word (Word32, Word16)
3640
import Control.Monad.IO.Class (MonadIO, liftIO)
3741
import Control.Exception
3842
( IOException
@@ -53,57 +57,73 @@ import System.Timeout (timeout)
5357

5458
#ifdef mingw32_HOST_OS
5559

56-
foreign import stdcall unsafe "htonl" htonl :: CInt -> CInt
57-
foreign import stdcall unsafe "ntohl" ntohl :: CInt -> CInt
58-
foreign import stdcall unsafe "htons" htons :: CShort -> CShort
59-
foreign import stdcall unsafe "ntohs" ntohs :: CShort -> CShort
60+
foreign import stdcall unsafe "htonl" htonl :: Word32 -> Word32
61+
foreign import stdcall unsafe "ntohl" ntohl :: Word32 -> Word32
62+
foreign import stdcall unsafe "htons" htons :: Word16 -> Word16
63+
foreign import stdcall unsafe "ntohs" ntohs :: Word16 -> Word16
6064

6165
#else
6266

63-
foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
64-
foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
65-
foreign import ccall unsafe "htons" htons :: CShort -> CShort
66-
foreign import ccall unsafe "ntohs" ntohs :: CShort -> CShort
67+
foreign import ccall unsafe "htonl" htonl :: Word32 -> Word32
68+
foreign import ccall unsafe "ntohl" ntohl :: Word32 -> Word32
69+
foreign import ccall unsafe "htons" htons :: Word16 -> Word16
70+
foreign import ccall unsafe "ntohs" ntohs :: Word16 -> Word16
6771

6872
#endif
6973

7074
-- | Serialize 32-bit to network byte order
71-
encodeInt32 :: Enum a => a -> ByteString
72-
encodeInt32 i32 =
75+
encodeWord32 :: Word32 -> ByteString
76+
encodeWord32 w32 =
7377
BSI.unsafeCreate 4 $ \p ->
74-
pokeByteOff p 0 (htonl . fromIntegral . fromEnum $ i32)
78+
pokeByteOff p 0 (htonl w32)
7579

7680
-- | Deserialize 32-bit from network byte order
77-
-- Throws an IO exception if this is not a valid integer.
78-
decodeInt32 :: Num a => ByteString -> a
79-
decodeInt32 bs
80-
| BS.length bs /= 4 = throw $ userError "decodeInt32: Invalid length"
81+
-- Throws an IO exception if this is not exactly 32 bits.
82+
decodeWord32 :: ByteString -> Word32
83+
decodeWord32 bs
84+
| BS.length bs /= 4 = throw $ userError "decodeWord32: not 4 bytes"
8185
| otherwise = BSI.inlinePerformIO $ do
8286
let (fp, offset, _) = BSI.toForeignPtr bs
83-
withForeignPtr fp $ \p -> do
84-
w32 <- peekByteOff p offset
85-
return (fromIntegral . ntohl $ w32)
87+
withForeignPtr fp $ \p -> ntohl <$> peekByteOff p offset
8688

8789
-- | Serialize 16-bit to network byte order
88-
encodeInt16 :: Enum a => a -> ByteString
89-
encodeInt16 i16 =
90+
encodeWord16 :: Word16 -> ByteString
91+
encodeWord16 w16 =
9092
BSI.unsafeCreate 2 $ \p ->
91-
pokeByteOff p 0 (htons . fromIntegral . fromEnum $ i16)
93+
pokeByteOff p 0 (htons w16)
9294

9395
-- | Deserialize 16-bit from network byte order
94-
-- Throws an IO exception if this is not a valid integer
95-
decodeInt16 :: Num a => ByteString -> a
96-
decodeInt16 bs
97-
| BS.length bs /= 2 = throw $ userError "decodeInt16: Invalid length"
96+
-- Throws an IO exception if this is not exactly 16 bits.
97+
decodeWord16 :: ByteString -> Word16
98+
decodeWord16 bs
99+
| BS.length bs /= 2 = throw $ userError "decodeWord16: not 2 bytes"
98100
| otherwise = BSI.inlinePerformIO $ do
99101
let (fp, offset, _) = BSI.toForeignPtr bs
100-
withForeignPtr fp $ \p -> do
101-
w16 <- peekByteOff p offset
102-
return (fromIntegral . ntohs $ w16)
102+
withForeignPtr fp $ \p -> ntohs <$> peekByteOff p offset
103+
104+
-- | Encode an Enum in 32 bits by encoding its signed Int equivalent (beware
105+
-- of truncation, an Enum may contain more than 2^32 points).
106+
encodeEnum32 :: Enum a => a -> ByteString
107+
encodeEnum32 = encodeWord32 . fromIntegral . fromEnum
108+
109+
-- | Decode any Num type from 32 bits by using fromIntegral to convert from
110+
-- a Word32.
111+
decodeNum32 :: Num a => ByteString -> a
112+
decodeNum32 = fromIntegral . decodeWord32
113+
114+
-- | Encode an Enum in 16 bits by encoding its signed Int equivalent (beware
115+
-- of truncation, an Enum may contain more than 2^16 points).
116+
encodeEnum16 :: Enum a => a -> ByteString
117+
encodeEnum16 = encodeWord16 . fromIntegral . fromEnum
118+
119+
-- | Decode any Num type from 16 bits by using fromIntegral to convert from
120+
-- a Word16.
121+
decodeNum16 :: Num a => ByteString -> a
122+
decodeNum16 = fromIntegral . decodeWord16
103123

104124
-- | Prepend a list of bytestrings with their total length
105125
prependLength :: [ByteString] -> [ByteString]
106-
prependLength bss = encodeInt32 (sum . map BS.length $ bss) : bss
126+
prependLength bss = encodeWord32 (fromIntegral . sum . map BS.length $ bss) : bss
107127

108128
-- | Translate exceptions that arise in IO computations
109129
mapIOException :: Exception e => (IOException -> e) -> IO a -> IO a

0 commit comments

Comments
 (0)