ip 1.7.3 → 1.7.4
raw patch · 6 files changed
+86/−11 lines, 6 filesdep ~aesondep ~attoparsecdep ~hashablePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, attoparsec, hashable
API changes (from Hackage documentation)
+ Net.IP: decodeUtf8Bytes :: Bytes -> Maybe IP
Files
- ip.cabal +2/−2
- src/Data/Word/Synthetic/Word12.hs +5/−0
- src/Net/IP.hs +11/−0
- src/Net/IPv4.hs +50/−8
- src/Net/Mac.hs +11/−1
- test/Test.hs +7/−0
ip.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: ip-version: 1.7.3+version: 1.7.4 synopsis: Library for IP and MAC addresses homepage: https://github.com/andrewthad/haskell-ip#readme license: BSD-3-Clause@@ -46,7 +46,7 @@ Data.Text.Builder.Variable Data.Word.Synthetic.Word12 build-depends:- , aeson >= 1.0 && < 1.6+ , aeson >= 1.0 && < 2.1 , attoparsec >= 0.13 && < 0.14 , base >= 4.9 && < 5 , byteslice >= 0.1.2 && < 0.3
src/Data/Word/Synthetic/Word12.hs view
@@ -33,7 +33,12 @@ import GHC.Arr import GHC.Base import GHC.Enum+#if MIN_VERSION_base(4,15,0)+import GHC.Integer (integerToWord, smallInteger)+import GHC.Num hiding (integerToWord)+#else import GHC.Num+#endif import GHC.Read import GHC.Real import GHC.Show
src/Net/IP.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-}@@ -46,6 +47,7 @@ , decodeShort , boundedBuilderUtf8 -- ** Bytes+ , decodeUtf8Bytes , parserUtf8Bytes -- ** Printing , print@@ -72,6 +74,7 @@ import qualified Arithmetic.Lte as Lte import qualified Data.Aeson as Aeson+import qualified Data.Bytes as Bytes import qualified Data.Bytes.Builder.Bounded as BB import qualified Data.Text.IO as TIO import qualified Data.Bytes.Parser as Parser@@ -178,6 +181,14 @@ decodeShort t | Just x <- IPv4.decodeShort t = Just (fromIPv4 x) | otherwise = coerce (IPv6.decodeShort t)++-- | Decode UTF-8-encoded 'Bytes' into an 'IP' address.+decodeUtf8Bytes :: Bytes.Bytes -> Maybe IP+decodeUtf8Bytes !b = case Parser.parseBytes (parserUtf8Bytes ()) b of+ Parser.Success (Parser.Slice _ len addr) -> case len of+ 0 -> Just addr+ _ -> Nothing+ Parser.Failure _ -> Nothing -- | Parse UTF-8-encoded 'Bytes' as an 'IP' address. parserUtf8Bytes :: e -> Parser.Parser e s IP
src/Net/IPv4.hs view
@@ -137,6 +137,7 @@ import qualified Data.Bytes as Bytes import qualified Data.Bytes.Parser as Parser import qualified Data.Bytes.Parser.Latin as Latin+import qualified Data.Char as Char import qualified Data.Primitive as PM import qualified Data.Text as Text import qualified Data.Text.Array as TArray@@ -153,6 +154,10 @@ import qualified Data.Vector.Unboxed as UVector import qualified Data.Vector.Unboxed.Mutable as MUVector +#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as AesonKey+#endif+ -- $setup -- -- These are here to get doctest's property checking to work@@ -697,8 +702,14 @@ instance ToJSONKey IPv4 where toJSONKey = ToJSONKeyText- encode+ (keyFromText . encode) (\addr -> Aeson.unsafeToEncoding $ Builder.char7 '"' <> builderUtf8 addr <> Builder.char7 '"')+ where+#if MIN_VERSION_aeson(2,0,0)+ keyFromText = AesonKey.fromText+#else+ keyFromText = id+#endif instance FromJSONKey IPv4 where fromJSONKey = FromJSONKeyTextParser aesonParser@@ -721,16 +732,47 @@ decodeIPv4TextReader :: TextRead.Reader IPv4 decodeIPv4TextReader t1' = do- (a,t2) <- TextRead.decimal t1'+ (a,t2) <- readOctet t1' t2' <- stripDecimal t2- (b,t3) <- TextRead.decimal t2'+ (b,t3) <- readOctet t2' t3' <- stripDecimal t3- (c,t4) <- TextRead.decimal t3'+ (c,t4) <- readOctet t3' t4' <- stripDecimal t4- (d,t5) <- TextRead.decimal t4'- if a > 255 || b > 255 || c > 255 || d > 255- then Left ipOctetSizeErrorMsg- else Right (fromOctets' a b c d,t5)+ (d,t5) <- readOctet t4'+ Right (fromOctets' a b c d,t5)++-- | Read an IPv4 octet (@0 <= n <= 255@)+--+-- The input must begin with at least one decimal digit. Input is consumed+-- until a non-digit is reached, the end of the input is reached, or the+-- accumulated value exceeds the maximum bound (255). As with+-- 'TextRead.decimal', any number of leading zeros are permitted.+--+-- Optimizations:+--+-- * The 'Char.isDigit' and 'Char.digitToInt' functions are avoided in order+-- to avoiding checking the range more than once. This implementation calls+-- 'Char.ord' (once) and uses the result for both the range check and the+-- calculation.+-- * The type of the accumulated value is 'Int', allowing for a single+-- 'fromIntegral' call instead of one for each digit. This is possible+-- because the maximum bound (255) is sufficiently less than the maximum+-- bound of 'Int'. Specifically: @255 * 10 + Char.ord '9' <= maxBound@+-- * This implementation does not make use of @UnboxedTuples@ because the+-- @span_@ function is part of the internal API. Additional performance+-- could be gained by using this internal API function.+readOctet :: TextRead.Reader Word+readOctet t = do+ let (digits, rest) = Text.span Char.isDigit t+ when (Text.null digits) $ Left "octet does not start with a digit"+ case Text.foldr go Just digits 0 of+ Just n -> Right (fromIntegral n, rest)+ Nothing -> Left ipOctetSizeErrorMsg+ where+ go :: Char -> (Int -> Maybe Int) -> Int -> Maybe Int+ go !d !f !n =+ let n' = n * 10 + Char.ord d - 48+ in if n' <= 255 then f n' else Nothing stripDecimal :: Text -> Either String Text stripDecimal t = case Text.uncons t of
src/Net/Mac.hs view
@@ -103,6 +103,10 @@ import qualified Data.Text.Short.Unsafe as TS import qualified Data.Text as Text () +#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as AK+#endif+ -- $setup -- -- These are here to get doctest's property checking to work@@ -858,8 +862,14 @@ instance ToJSONKey Mac where toJSONKey = ToJSONKeyText- encode+ (keyFromText . encode) (\m -> Aeson.unsafeToEncoding $ BB.char7 '"' <> builderUtf8 m <> BB.char7 '"')+ where+#if MIN_VERSION_aeson(2,0,0)+ keyFromText = AK.fromText+#else+ keyFromText = id+#endif instance FromJSONKey Mac where fromJSONKey = FromJSONKeyTextParser $ \t -> case decode t of
test/Test.hs view
@@ -140,6 +140,12 @@ , PH.testCase "S" $ IPv4.reserved (IPv4.ipv4 192 88 99 0) @=? True , PH.testCase "T" $ IPv4.reserved (IPv4.ipv4 192 0 1 0) @=? False ]+ , testGroup "private"+ [ PH.testCase "A" $ IPv4.private (IPv4.ipv4 198 73 8 38) @=? False+ , PH.testCase "B" $ IPv4.private (IPv4.ipv4 192 168 100 5) @=? True+ , PH.testCase "C" $ IPv4.private (IPv4.ipv4 10 0 0 0) @=? True+ , PH.testCase "D" $ IPv4.private (IPv4.ipv4 10 255 255 255) @=? True+ ] ] , testGroup "IPv6 Range Operations" [ testProperty "Idempotence of normalizing IPv6 range"@@ -413,6 +419,7 @@ , "1.9.x.2" , "1.9.3" , "1.9"+ , "127.0.0.18446744073709551617" ] testDecodeFailures :: [TestTree]