ip 1.5.0 → 1.5.1
raw patch · 3 files changed
+95/−27 lines, 3 filesdep ~hashablePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hashable
API changes (from Hackage documentation)
+ Net.IP: isIPv4 :: IP -> Bool
+ Net.IP: isIPv6 :: IP -> Bool
Files
- ip.cabal +4/−4
- src/Net/IP.hs +64/−12
- src/Net/IPv4.hs +27/−11
ip.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.0 name: ip-version: 1.5.0+version: 1.5.1 synopsis: Library for IP and MAC addresses homepage: https://github.com/andrewthad/haskell-ip#readme license: BSD3@@ -50,9 +50,9 @@ , aeson >= 1.0 && < 1.5 , attoparsec >= 0.13 && < 0.14 , bytestring >= 0.10 && < 0.11- , deepseq >= 1.4 && < 1.5 - , hashable >= 1.2 && < 1.3- , primitive >= 0.6 && < 0.7+ , deepseq >= 1.4 && < 1.5+ , hashable >= 1.2 && < 1.4+ , primitive >= 0.6.4 && < 0.8 , text >= 1.2 && < 1.3 , vector >= 0.11 && < 0.13 , wide-word >= 0.1.0.8 && < 0.2
src/Net/IP.hs view
@@ -17,9 +17,9 @@ All functions and instance methods that deal with textual conversion will encode an 'IP' using either dot-decimal notation (for IPv4) or RFC 5952 (for IPv6). They will decode an 'IP' from either format- as well. The 'Show' instance presents an address in as valid haskell code + as well. The 'Show' instance presents an address in as valid haskell code that resembles the formatted address:- + >>> decode "192.168.3.100" Just (ipv4 192 168 3 100) >>> decode "A3F5:12:F26::1466:8B91"@@ -29,6 +29,8 @@ module Net.IP ( -- * Pattern Matching case_+ , isIPv4+ , isIPv6 -- * Construction , ipv4 , ipv6@@ -44,23 +46,26 @@ , IP(..) ) where -import Prelude hiding (print) import Control.DeepSeq (NFData)-import Data.Bits-import GHC.Generics (Generic)-import Net.IPv6 (IPv6(..))-import Net.IPv4 (IPv4(..))-import Text.Read (Read(..))-import Text.ParserCombinators.ReadPrec ((+++)) import Data.Aeson (FromJSON(..),ToJSON(..))+import Data.Bits import Data.Text (Text) import Data.WideWord (Word128(..)) import Data.Word (Word8,Word16)-import qualified Net.IPv4 as IPv4-import qualified Net.IPv6 as IPv6+import GHC.Generics (Generic)+import Net.IPv4 (IPv4(..))+import Net.IPv6 (IPv6(..))+import Prelude hiding (print)+import Text.ParserCombinators.ReadPrec ((+++))+import Text.Read (Read(..)) import qualified Data.Aeson as Aeson import qualified Data.Text.IO as TIO+import qualified Net.IPv4 as IPv4+import qualified Net.IPv6 as IPv6 +-- $setup+-- >>> :set -XOverloadedStrings+ -- | Run a function over an 'IP' depending on its status -- as an 'IPv4' or 'IPv6'. --@@ -99,10 +104,28 @@ fromIPv6 = IP -- | Encode an 'IP' as 'Text'.+--+-- >>> encode (ipv4 10 0 0 25)+-- "10.0.0.25"+--+-- >>> encode (ipv6 0x3124 0x0 0x0 0xDEAD 0xCAFE 0xFF 0xFE00 0x1)+-- "3124::dead:cafe:ff:fe00:1" encode :: IP -> Text encode = case_ IPv4.encode IPv6.encode -- | Decode an 'IP' from 'Text'.+--+-- >>> decode "10.0.0.25"+-- Just (ipv4 10 0 0 25)+--+-- >>> fmap isIPv4 (decode "10.0.0.25")+-- Just True+--+-- >>> decode "3124::dead:cafe:ff:fe00:1"+-- Just (ipv6 0x3124 0x0000 0x0000 0xdead 0xcafe 0x00ff 0xfe00 0x0001)+--+-- >>> fmap isIPv6 (decode "3124::dead:cafe:ff:fe00:1")+-- Just True decode :: Text -> Maybe IP decode t = case IPv4.decode t of Nothing -> case IPv6.decode t of@@ -110,7 +133,36 @@ Just v6 -> Just (fromIPv6 v6) Just v4 -> Just (fromIPv4 v4) --- | Print an 'IP' using the textual encoding.+-- | Is the 'IP' an IPv4 address?+--+-- >>> isIPv4 (ipv4 10 0 0 25)+-- True+--+-- >>> isIPv4 (ipv6 0x3124 0x0 0x0 0xDEAD 0xCAFE 0xFF 0xFE00 0x1)+-- False+isIPv4 :: IP -> Bool+isIPv4 = case_ (const True) (const False)+{-# inline isIPv4 #-}++-- | Is the 'IP' an IPv6 address?+--+-- >>> isIPv6 (ipv4 10 0 0 25)+-- False+--+-- >>> isIPv6 (ipv6 0x3124 0x0 0x0 0xDEAD 0xCAFE 0xFF 0xFE00 0x1)+-- True+isIPv6 :: IP -> Bool+isIPv6 = case_ (const False) (const True)+{-# inline isIPv6 #-}++-- | Print an 'IP' using the textual encoding. This exists mostly for+-- debugging purposes.+--+-- >>> print (ipv4 10 0 0 25)+-- 10.0.0.25+--+-- >>> print (ipv6 0x3124 0x0 0x0 0xDEAD 0xCAFE 0xFF 0xFE00 0x1)+-- 3124::dead:cafe:ff:fe00:1 print :: IP -> IO () print = TIO.putStrLn . encode
src/Net/IPv4.hs view
@@ -122,6 +122,7 @@ -- -- These are here to get doctest's property checking to work --+-- >>> :set -XOverloadedStrings -- >>> import Test.QuickCheck (Arbitrary(..)) -- >>> import qualified Prelude as P -- >>> import qualified Data.Text.IO as T@@ -262,10 +263,10 @@ -- | Decode an 'IPv4' address. ----- >>> decode (Text.pack "192.168.2.47")+-- >>> decode "192.168.2.47" -- Just (ipv4 192 168 2 47) ----- >>> decode (Text.pack "10.100.256.256")+-- >>> decode "10.100.256.256" -- Nothing decode :: Text -> Maybe IPv4 decode = decodeIPv4TextMaybe@@ -279,20 +280,20 @@ -- | Parse an 'IPv4' address using a 'TextRead.Reader'. ----- >>> reader (Text.pack "192.168.2.47")+-- >>> reader "192.168.2.47" -- Right (ipv4 192 168 2 47,"") ----- >>> reader (Text.pack "192.168.2.470")+-- >>> reader "192.168.2.470" -- Left "All octets in an IPv4 address must be between 0 and 255" reader :: TextRead.Reader IPv4 reader = decodeIPv4TextReader -- | Parse an 'IPv4' address using a 'AT.Parser'. ----- >>> AT.parseOnly parser (Text.pack "192.168.2.47")+-- >>> AT.parseOnly parser "192.168.2.47" -- Right (ipv4 192 168 2 47) ----- >>> AT.parseOnly parser (Text.pack "192.168.2.470")+-- >>> AT.parseOnly parser "192.168.2.470" -- Left "Failed reading: All octets in an IPv4 address must be between 0 and 255" parser :: AT.Parser IPv4 parser = dotDecimalParser@@ -345,7 +346,7 @@ -- | Decode a UTF8-encoded 'ByteString' into an 'IPv4'. ----- >>> decodeUtf8 (BC8.pack "192.168.2.47")+-- >>> decodeUtf8 "192.168.2.47" -- Just (ipv4 192 168 2 47) decodeUtf8 :: ByteString -> Maybe IPv4 decodeUtf8 = decode <=< rightToMaybe . decodeUtf8'@@ -358,10 +359,10 @@ -- | Parse an 'IPv4' using a 'AB.Parser'. ----- >>> AB.parseOnly parserUtf8 (BC8.pack "192.168.2.47")+-- >>> AB.parseOnly parserUtf8 "192.168.2.47" -- Right (ipv4 192 168 2 47) ----- >>> AB.parseOnly parserUtf8 (BC8.pack "192.168.2.470")+-- >>> AB.parseOnly parserUtf8 "192.168.2.470" -- Left "Failed reading: All octets in an ipv4 address must be between 0 and 255" parserUtf8 :: AB.Parser IPv4 parserUtf8 = fromOctets'@@ -882,18 +883,32 @@ in IPv4Range (IPv4 w') len' -- | Encode an 'IPv4Range' as 'Text'.+--+-- >>> encodeRange (IPv4Range (ipv4 172 16 0 0) 12)+-- "172.16.0.0/12" encodeRange :: IPv4Range -> Text encodeRange = rangeToDotDecimalText -- | Decode an 'IPv4Range' from 'Text'.+--+-- >>> decodeRange "172.16.0.0/12"+-- Just (IPv4Range {ipv4RangeBase = ipv4 172 16 0 0, ipv4RangeLength = 12})+-- >>> decodeRange "192.168.25.254/16"+-- Just (IPv4Range {ipv4RangeBase = ipv4 192 168 0 0, ipv4RangeLength = 16}) decodeRange :: Text -> Maybe IPv4Range decodeRange = rightToMaybe . AT.parseOnly (parserRange <* AT.endOfInput) -- | Encode an 'IPv4Range' to a 'TBuilder.Builder'.+--+-- >>> builderRange (IPv4Range (ipv4 172 16 0 0) 12)+-- "172.16.0.0/12" builderRange :: IPv4Range -> TBuilder.Builder builderRange = rangeToDotDecimalBuilder --- | Parse an 'IPv4Range' using a 'AT.Parser.'+-- | Parse an 'IPv4Range' using a 'AT.Parser'.+--+-- >>> AT.parseOnly parserRange "192.168.25.254/16"+-- Right (IPv4Range {ipv4RangeBase = ipv4 192 168 0 0, ipv4RangeLength = 16}) parserRange :: AT.Parser IPv4Range parserRange = do ip <- parser@@ -906,7 +921,8 @@ then fail "An IP range length must be between 0 and 32" else return i --- | This exists mostly for testing purposes.+-- | Print an 'IPv4Range'. Helper function that+-- exists mostly for testing purposes. printRange :: IPv4Range -> IO () printRange = TIO.putStrLn . encodeRange