X-Git-Url: https://gitweb.michael.orlitzky.com/?p=hath.git;a=blobdiff_plain;f=src%2FIPv4Address.hs;h=85d86616023b19f3cc936ac2f69f1b65020df880;hp=7e502125722cbfb354a53d517acd206a3fe678ad;hb=71f626d17e4308e00a894d088626bb72322dedec;hpb=a1a1484ae97e3543496c32f326ac0952ac7f7103 diff --git a/src/IPv4Address.hs b/src/IPv4Address.hs index 7e50212..85d8661 100644 --- a/src/IPv4Address.hs +++ b/src/IPv4Address.hs @@ -5,6 +5,7 @@ module IPv4Address( most_sig_bit_different ) where +import Data.Word (Word32) import Test.Tasty ( TestTree, testGroup ) import Test.Tasty.HUnit ( (@?=), testCase ) @@ -188,18 +189,26 @@ instance Enum IPv4Address where -- | Convert an 'Int' @x@ to an 'IPv4Address'. Each octet of @x@ is -- right-shifted by the appropriate number of bits, and the fractional -- part is dropped. - toEnum x = + toEnum y = IPv4Address oct1 oct2 oct3 oct4 where + -- Convert the input Int to a Word32 before we proceed. On x86, + -- the Int that we get could be negative (half of all IP + -- addresses correspond to negative numbers), and then the magic + -- below doesn't work. The Word32 type is unsigned, so we do the + -- math on that and then convert everything back to Int later on + -- once we have four much-smaller non-negative numbers. + x = fromIntegral y :: Word32 + -- Chop off the higher octets. x1 = x `mod` 2^32, would be -- redundant. x2 = x `mod` 2^(24 :: Integer) x3 = x `mod` 2^(16 :: Integer) - x4 = x `mod` 2^(8 :: Integer) + x4 = (fromIntegral $ x `mod` 2^(8 :: Integer)) :: Int -- Perform right-shifts. x4 doesn't need a shift. - shifted_x1 = x `quot` 2^(24 :: Integer) - shifted_x2 = x2 `quot` 2^(16 :: Integer) - shifted_x3 = x3 `quot` 2^(8 :: Integer) + shifted_x1 = (fromIntegral $ x `quot` 2^(24 :: Integer)) :: Int + shifted_x2 = (fromIntegral $ x2 `quot` 2^(16 :: Integer)) :: Int + shifted_x3 = fromIntegral $ x3 `quot` 2^(8 :: Integer) :: Int oct1 = toEnum shifted_x1 :: Octet oct2 = toEnum shifted_x2 :: Octet oct3 = toEnum shifted_x3 :: Octet @@ -432,7 +441,11 @@ test_to_enum = where desc = "192.168.0.0 in base-10 is 3232235520" expected = mk_testaddr 192 168 0 0 - actual = toEnum 3232235520 :: IPv4Address + -- We declare the big number as Word32 because otherwise, on x86, + -- we get a warning that it's too big to fit in a 32-bit integer. + -- Ultimately we convert it to a (negative) Int on those systems + -- anyway, but the gymnastics declare our intent to the compiler. + actual = toEnum (fromIntegral (3232235520 :: Word32)) :: IPv4Address test_ord_instance1 :: TestTree