{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DuplicateRecordFields      #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs               #-}

module HaskellWorks.Data.Network.Ip.Ipv4
  ( IpAddress(..)
  , IpNetMask(..)
  , IpBlock(..)
  , Unaligned, Canonical
  , bitPower
  , isCanonical
  , splitBlock
  , parseIpAddress
  , parseIpAddressAsBlock
  , showIpAddress
  , showsIpAddress
  , tshowIpAddress
  , tshowIpBlock
  , wordsToIpAddress
  , ipAddressToWords
  , firstIpAddress
  , lastIpAddress
  , canonicaliseIpBlock
  , collapseIpBlocks
  , splitIpRange
  , rangeToBlocksDL
  , rangeToBlocks
  , blockToRange
  ) where

import Control.Applicative                   ((<|>))
import Data.Bifunctor
import Data.Foldable
import Data.Word
import Foreign.Storable
import GHC.Generics
import HaskellWorks.Data.Bits.BitWise
import HaskellWorks.Data.Network.Ip.Range
import HaskellWorks.Data.Network.Ip.SafeEnum
import HaskellWorks.Data.Network.Ip.Validity

import qualified Data.Bits                                   as B
import qualified Data.Sequence                               as S
import qualified Data.Text                                   as T
import qualified HaskellWorks.Data.Network.Ip.Internal.Appar as I
import qualified Text.Appar.String                           as AP

newtype IpAddress = IpAddress
  { IpAddress -> Word32
word :: Word32
  } deriving (Int -> IpAddress
IpAddress -> Int
IpAddress -> [IpAddress]
IpAddress -> IpAddress
IpAddress -> IpAddress -> [IpAddress]
IpAddress -> IpAddress -> IpAddress -> [IpAddress]
(IpAddress -> IpAddress)
-> (IpAddress -> IpAddress)
-> (Int -> IpAddress)
-> (IpAddress -> Int)
-> (IpAddress -> [IpAddress])
-> (IpAddress -> IpAddress -> [IpAddress])
-> (IpAddress -> IpAddress -> [IpAddress])
-> (IpAddress -> IpAddress -> IpAddress -> [IpAddress])
-> Enum IpAddress
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: IpAddress -> IpAddress -> IpAddress -> [IpAddress]
$cenumFromThenTo :: IpAddress -> IpAddress -> IpAddress -> [IpAddress]
enumFromTo :: IpAddress -> IpAddress -> [IpAddress]
$cenumFromTo :: IpAddress -> IpAddress -> [IpAddress]
enumFromThen :: IpAddress -> IpAddress -> [IpAddress]
$cenumFromThen :: IpAddress -> IpAddress -> [IpAddress]
enumFrom :: IpAddress -> [IpAddress]
$cenumFrom :: IpAddress -> [IpAddress]
fromEnum :: IpAddress -> Int
$cfromEnum :: IpAddress -> Int
toEnum :: Int -> IpAddress
$ctoEnum :: Int -> IpAddress
pred :: IpAddress -> IpAddress
$cpred :: IpAddress -> IpAddress
succ :: IpAddress -> IpAddress
$csucc :: IpAddress -> IpAddress
Enum, IpAddress
IpAddress -> IpAddress -> Bounded IpAddress
forall a. a -> a -> Bounded a
maxBound :: IpAddress
$cmaxBound :: IpAddress
minBound :: IpAddress
$cminBound :: IpAddress
Bounded, IpAddress -> IpAddress -> Bool
(IpAddress -> IpAddress -> Bool)
-> (IpAddress -> IpAddress -> Bool) -> Eq IpAddress
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IpAddress -> IpAddress -> Bool
$c/= :: IpAddress -> IpAddress -> Bool
== :: IpAddress -> IpAddress -> Bool
$c== :: IpAddress -> IpAddress -> Bool
Eq, Eq IpAddress
Eq IpAddress
-> (IpAddress -> IpAddress -> Ordering)
-> (IpAddress -> IpAddress -> Bool)
-> (IpAddress -> IpAddress -> Bool)
-> (IpAddress -> IpAddress -> Bool)
-> (IpAddress -> IpAddress -> Bool)
-> (IpAddress -> IpAddress -> IpAddress)
-> (IpAddress -> IpAddress -> IpAddress)
-> Ord IpAddress
IpAddress -> IpAddress -> Bool
IpAddress -> IpAddress -> Ordering
IpAddress -> IpAddress -> IpAddress
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: IpAddress -> IpAddress -> IpAddress
$cmin :: IpAddress -> IpAddress -> IpAddress
max :: IpAddress -> IpAddress -> IpAddress
$cmax :: IpAddress -> IpAddress -> IpAddress
>= :: IpAddress -> IpAddress -> Bool
$c>= :: IpAddress -> IpAddress -> Bool
> :: IpAddress -> IpAddress -> Bool
$c> :: IpAddress -> IpAddress -> Bool
<= :: IpAddress -> IpAddress -> Bool
$c<= :: IpAddress -> IpAddress -> Bool
< :: IpAddress -> IpAddress -> Bool
$c< :: IpAddress -> IpAddress -> Bool
compare :: IpAddress -> IpAddress -> Ordering
$ccompare :: IpAddress -> IpAddress -> Ordering
$cp1Ord :: Eq IpAddress
Ord, (forall x. IpAddress -> Rep IpAddress x)
-> (forall x. Rep IpAddress x -> IpAddress) -> Generic IpAddress
forall x. Rep IpAddress x -> IpAddress
forall x. IpAddress -> Rep IpAddress x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep IpAddress x -> IpAddress
$cfrom :: forall x. IpAddress -> Rep IpAddress x
Generic, IpAddress -> Maybe IpAddress
(IpAddress -> Maybe IpAddress)
-> (IpAddress -> Maybe IpAddress) -> SafeEnum IpAddress
forall a. (a -> Maybe a) -> (a -> Maybe a) -> SafeEnum a
safeSucc :: IpAddress -> Maybe IpAddress
$csafeSucc :: IpAddress -> Maybe IpAddress
safePred :: IpAddress -> Maybe IpAddress
$csafePred :: IpAddress -> Maybe IpAddress
SafeEnum, Ptr b -> Int -> IO IpAddress
Ptr b -> Int -> IpAddress -> IO ()
Ptr IpAddress -> IO IpAddress
Ptr IpAddress -> Int -> IO IpAddress
Ptr IpAddress -> Int -> IpAddress -> IO ()
Ptr IpAddress -> IpAddress -> IO ()
IpAddress -> Int
(IpAddress -> Int)
-> (IpAddress -> Int)
-> (Ptr IpAddress -> Int -> IO IpAddress)
-> (Ptr IpAddress -> Int -> IpAddress -> IO ())
-> (forall b. Ptr b -> Int -> IO IpAddress)
-> (forall b. Ptr b -> Int -> IpAddress -> IO ())
-> (Ptr IpAddress -> IO IpAddress)
-> (Ptr IpAddress -> IpAddress -> IO ())
-> Storable IpAddress
forall b. Ptr b -> Int -> IO IpAddress
forall b. Ptr b -> Int -> IpAddress -> IO ()
forall a.
(a -> Int)
-> (a -> Int)
-> (Ptr a -> Int -> IO a)
-> (Ptr a -> Int -> a -> IO ())
-> (forall b. Ptr b -> Int -> IO a)
-> (forall b. Ptr b -> Int -> a -> IO ())
-> (Ptr a -> IO a)
-> (Ptr a -> a -> IO ())
-> Storable a
poke :: Ptr IpAddress -> IpAddress -> IO ()
$cpoke :: Ptr IpAddress -> IpAddress -> IO ()
peek :: Ptr IpAddress -> IO IpAddress
$cpeek :: Ptr IpAddress -> IO IpAddress
pokeByteOff :: Ptr b -> Int -> IpAddress -> IO ()
$cpokeByteOff :: forall b. Ptr b -> Int -> IpAddress -> IO ()
peekByteOff :: Ptr b -> Int -> IO IpAddress
$cpeekByteOff :: forall b. Ptr b -> Int -> IO IpAddress
pokeElemOff :: Ptr IpAddress -> Int -> IpAddress -> IO ()
$cpokeElemOff :: Ptr IpAddress -> Int -> IpAddress -> IO ()
peekElemOff :: Ptr IpAddress -> Int -> IO IpAddress
$cpeekElemOff :: Ptr IpAddress -> Int -> IO IpAddress
alignment :: IpAddress -> Int
$calignment :: IpAddress -> Int
sizeOf :: IpAddress -> Int
$csizeOf :: IpAddress -> Int
Storable)

instance Show IpAddress where
  showsPrec :: Int -> IpAddress -> ShowS
showsPrec Int
_ = IpAddress -> ShowS
showsIpAddress

instance Read IpAddress where
  readsPrec :: Int -> String -> [(IpAddress, String)]
  readsPrec :: Int -> ReadS IpAddress
readsPrec = Parser IpAddress -> Int -> ReadS IpAddress
forall a. Parser a -> Int -> String -> [(a, String)]
I.readsPrecOnParser (Word32 -> IpAddress
IpAddress (Word32 -> IpAddress) -> MkParser String Word32 -> Parser IpAddress
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MkParser String Word32
I.ipv4Address)

newtype IpNetMask = IpNetMask
  { IpNetMask -> Word8
word8 :: Word8
  } deriving (Int -> IpNetMask
IpNetMask -> Int
IpNetMask -> [IpNetMask]
IpNetMask -> IpNetMask
IpNetMask -> IpNetMask -> [IpNetMask]
IpNetMask -> IpNetMask -> IpNetMask -> [IpNetMask]
(IpNetMask -> IpNetMask)
-> (IpNetMask -> IpNetMask)
-> (Int -> IpNetMask)
-> (IpNetMask -> Int)
-> (IpNetMask -> [IpNetMask])
-> (IpNetMask -> IpNetMask -> [IpNetMask])
-> (IpNetMask -> IpNetMask -> [IpNetMask])
-> (IpNetMask -> IpNetMask -> IpNetMask -> [IpNetMask])
-> Enum IpNetMask
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: IpNetMask -> IpNetMask -> IpNetMask -> [IpNetMask]
$cenumFromThenTo :: IpNetMask -> IpNetMask -> IpNetMask -> [IpNetMask]
enumFromTo :: IpNetMask -> IpNetMask -> [IpNetMask]
$cenumFromTo :: IpNetMask -> IpNetMask -> [IpNetMask]
enumFromThen :: IpNetMask -> IpNetMask -> [IpNetMask]
$cenumFromThen :: IpNetMask -> IpNetMask -> [IpNetMask]
enumFrom :: IpNetMask -> [IpNetMask]
$cenumFrom :: IpNetMask -> [IpNetMask]
fromEnum :: IpNetMask -> Int
$cfromEnum :: IpNetMask -> Int
toEnum :: Int -> IpNetMask
$ctoEnum :: Int -> IpNetMask
pred :: IpNetMask -> IpNetMask
$cpred :: IpNetMask -> IpNetMask
succ :: IpNetMask -> IpNetMask
$csucc :: IpNetMask -> IpNetMask
Enum, IpNetMask -> IpNetMask -> Bool
(IpNetMask -> IpNetMask -> Bool)
-> (IpNetMask -> IpNetMask -> Bool) -> Eq IpNetMask
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IpNetMask -> IpNetMask -> Bool
$c/= :: IpNetMask -> IpNetMask -> Bool
== :: IpNetMask -> IpNetMask -> Bool
$c== :: IpNetMask -> IpNetMask -> Bool
Eq, Eq IpNetMask
Eq IpNetMask
-> (IpNetMask -> IpNetMask -> Ordering)
-> (IpNetMask -> IpNetMask -> Bool)
-> (IpNetMask -> IpNetMask -> Bool)
-> (IpNetMask -> IpNetMask -> Bool)
-> (IpNetMask -> IpNetMask -> Bool)
-> (IpNetMask -> IpNetMask -> IpNetMask)
-> (IpNetMask -> IpNetMask -> IpNetMask)
-> Ord IpNetMask
IpNetMask -> IpNetMask -> Bool
IpNetMask -> IpNetMask -> Ordering
IpNetMask -> IpNetMask -> IpNetMask
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: IpNetMask -> IpNetMask -> IpNetMask
$cmin :: IpNetMask -> IpNetMask -> IpNetMask
max :: IpNetMask -> IpNetMask -> IpNetMask
$cmax :: IpNetMask -> IpNetMask -> IpNetMask
>= :: IpNetMask -> IpNetMask -> Bool
$c>= :: IpNetMask -> IpNetMask -> Bool
> :: IpNetMask -> IpNetMask -> Bool
$c> :: IpNetMask -> IpNetMask -> Bool
<= :: IpNetMask -> IpNetMask -> Bool
$c<= :: IpNetMask -> IpNetMask -> Bool
< :: IpNetMask -> IpNetMask -> Bool
$c< :: IpNetMask -> IpNetMask -> Bool
compare :: IpNetMask -> IpNetMask -> Ordering
$ccompare :: IpNetMask -> IpNetMask -> Ordering
$cp1Ord :: Eq IpNetMask
Ord, Int -> IpNetMask -> ShowS
[IpNetMask] -> ShowS
IpNetMask -> String
(Int -> IpNetMask -> ShowS)
-> (IpNetMask -> String)
-> ([IpNetMask] -> ShowS)
-> Show IpNetMask
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IpNetMask] -> ShowS
$cshowList :: [IpNetMask] -> ShowS
show :: IpNetMask -> String
$cshow :: IpNetMask -> String
showsPrec :: Int -> IpNetMask -> ShowS
$cshowsPrec :: Int -> IpNetMask -> ShowS
Show, (forall x. IpNetMask -> Rep IpNetMask x)
-> (forall x. Rep IpNetMask x -> IpNetMask) -> Generic IpNetMask
forall x. Rep IpNetMask x -> IpNetMask
forall x. IpNetMask -> Rep IpNetMask x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep IpNetMask x -> IpNetMask
$cfrom :: forall x. IpNetMask -> Rep IpNetMask x
Generic)

instance Bounded IpNetMask where
  minBound :: IpNetMask
minBound = Word8 -> IpNetMask
IpNetMask Word8
0
  maxBound :: IpNetMask
maxBound = Word8 -> IpNetMask
IpNetMask Word8
32

-- | An IP block.  The type parameter determines whether or not the value of the type is
-- canonical.
data IpBlock v = IpBlock
  { IpBlock v -> IpAddress
base :: !IpAddress
  , IpBlock v -> IpNetMask
mask :: !IpNetMask
  } deriving (IpBlock v -> IpBlock v -> Bool
(IpBlock v -> IpBlock v -> Bool)
-> (IpBlock v -> IpBlock v -> Bool) -> Eq (IpBlock v)
forall v. IpBlock v -> IpBlock v -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: IpBlock v -> IpBlock v -> Bool
$c/= :: forall v. IpBlock v -> IpBlock v -> Bool
== :: IpBlock v -> IpBlock v -> Bool
$c== :: forall v. IpBlock v -> IpBlock v -> Bool
Eq, Eq (IpBlock v)
Eq (IpBlock v)
-> (IpBlock v -> IpBlock v -> Ordering)
-> (IpBlock v -> IpBlock v -> Bool)
-> (IpBlock v -> IpBlock v -> Bool)
-> (IpBlock v -> IpBlock v -> Bool)
-> (IpBlock v -> IpBlock v -> Bool)
-> (IpBlock v -> IpBlock v -> IpBlock v)
-> (IpBlock v -> IpBlock v -> IpBlock v)
-> Ord (IpBlock v)
IpBlock v -> IpBlock v -> Bool
IpBlock v -> IpBlock v -> Ordering
IpBlock v -> IpBlock v -> IpBlock v
forall v. Eq (IpBlock v)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall v. IpBlock v -> IpBlock v -> Bool
forall v. IpBlock v -> IpBlock v -> Ordering
forall v. IpBlock v -> IpBlock v -> IpBlock v
min :: IpBlock v -> IpBlock v -> IpBlock v
$cmin :: forall v. IpBlock v -> IpBlock v -> IpBlock v
max :: IpBlock v -> IpBlock v -> IpBlock v
$cmax :: forall v. IpBlock v -> IpBlock v -> IpBlock v
>= :: IpBlock v -> IpBlock v -> Bool
$c>= :: forall v. IpBlock v -> IpBlock v -> Bool
> :: IpBlock v -> IpBlock v -> Bool
$c> :: forall v. IpBlock v -> IpBlock v -> Bool
<= :: IpBlock v -> IpBlock v -> Bool
$c<= :: forall v. IpBlock v -> IpBlock v -> Bool
< :: IpBlock v -> IpBlock v -> Bool
$c< :: forall v. IpBlock v -> IpBlock v -> Bool
compare :: IpBlock v -> IpBlock v -> Ordering
$ccompare :: forall v. IpBlock v -> IpBlock v -> Ordering
$cp1Ord :: forall v. Eq (IpBlock v)
Ord, (forall x. IpBlock v -> Rep (IpBlock v) x)
-> (forall x. Rep (IpBlock v) x -> IpBlock v)
-> Generic (IpBlock v)
forall x. Rep (IpBlock v) x -> IpBlock v
forall x. IpBlock v -> Rep (IpBlock v) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall v x. Rep (IpBlock v) x -> IpBlock v
forall v x. IpBlock v -> Rep (IpBlock v) x
$cto :: forall v x. Rep (IpBlock v) x -> IpBlock v
$cfrom :: forall v x. IpBlock v -> Rep (IpBlock v) x
Generic, IpBlock v
IpBlock v -> IpBlock v -> Bounded (IpBlock v)
forall v. IpBlock v
forall a. a -> a -> Bounded a
maxBound :: IpBlock v
$cmaxBound :: forall v. IpBlock v
minBound :: IpBlock v
$cminBound :: forall v. IpBlock v
Bounded)

instance Show (IpBlock v) where
  showsPrec :: Int -> IpBlock v -> ShowS
showsPrec Int
_ = IpBlock v -> ShowS
forall v. IpBlock v -> ShowS
showsIpBlock

instance Read (IpBlock Unaligned) where
  readsPrec :: Int -> ReadS (IpBlock Unaligned)
readsPrec = Parser (IpBlock Unaligned) -> Int -> ReadS (IpBlock Unaligned)
forall a. Parser a -> Int -> String -> [(a, String)]
I.readsPrecOnParser (Parser (IpBlock Unaligned) -> Parser (IpBlock Unaligned)
forall inp a. MkParser inp a -> MkParser inp a
AP.try Parser (IpBlock Unaligned)
parseUnalignedIpBlock Parser (IpBlock Unaligned)
-> Parser (IpBlock Unaligned) -> Parser (IpBlock Unaligned)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (IpBlock Unaligned)
forall v. Parser (IpBlock v)
parseIpAddressAsBlock)

instance Read (IpBlock Canonical) where
  readsPrec :: Int -> ReadS (IpBlock Canonical)
readsPrec = Parser (IpBlock Canonical) -> Int -> ReadS (IpBlock Canonical)
forall a. Parser a -> Int -> String -> [(a, String)]
I.readsPrecOnParser (Parser (IpBlock Canonical) -> Parser (IpBlock Canonical)
forall inp a. MkParser inp a -> MkParser inp a
AP.try Parser (IpBlock Canonical)
parseCanonicalIpBlock Parser (IpBlock Canonical)
-> Parser (IpBlock Canonical) -> Parser (IpBlock Canonical)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (IpBlock Canonical)
forall v. Parser (IpBlock v)
parseIpAddressAsBlock)

-- | Canonicalise the block by zero-ing out the host bits
canonicaliseIpBlock :: IpBlock v -> IpBlock Canonical
canonicaliseIpBlock :: IpBlock v -> IpBlock Canonical
canonicaliseIpBlock (IpBlock (IpAddress Word32
w) (IpNetMask Word8
m)) = IpAddress -> IpNetMask -> IpBlock Canonical
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress Word32
newWord) (Word8 -> IpNetMask
IpNetMask Word8
m)
  where bp :: Count
bp = Word8 -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
32 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
m)
        newWord :: Word32
newWord = (Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
bp) Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Count
bp

firstIpAddress :: IpBlock v -> IpAddress
firstIpAddress :: IpBlock v -> IpAddress
firstIpAddress (IpBlock IpAddress
b IpNetMask
_) = IpAddress
b

lastIpAddress :: IpBlock v -> IpAddress
lastIpAddress :: IpBlock v -> IpAddress
lastIpAddress (IpBlock (IpAddress Word32
b) (IpNetMask Word8
m)) = Word32 -> IpAddress
IpAddress (Word32
b Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int
I.blockSize Word8
m) Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
1)

bitPower :: IpNetMask -> Word64
bitPower :: IpNetMask -> Count
bitPower (IpNetMask Word8
m) = Word8 -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
32 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
m)

-- | A valid block must have all host-bits set to zero after the mask is applied
isCanonical :: IpBlock v -> Bool
isCanonical :: IpBlock v -> Bool
isCanonical (IpBlock (IpAddress Word32
b) (IpNetMask Word8
m)) = ((Word32
b Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Word8 -> Count
I.bitPower Word8
m) Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Word8 -> Count
I.bitPower Word8
m) Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
b

splitBlock :: IpBlock Canonical -> Maybe (IpBlock Canonical, IpBlock Canonical)
splitBlock :: IpBlock Canonical -> Maybe (IpBlock Canonical, IpBlock Canonical)
splitBlock (IpBlock (IpAddress Word32
b) (IpNetMask Word8
m)) =
  if Word8
m Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
0 Bool -> Bool -> Bool
&& Word8
m Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
32
    then  let !hm :: Word8
hm       = Word8
m Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
1
              !halfMask :: IpNetMask
halfMask = Word8 -> IpNetMask
IpNetMask Word8
hm
              !c :: Word32
c        = Count -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Count
0x100000000 :: Word64) Count -> Count -> Count
forall a. Shift a => a -> Count -> a
.>. Word8 -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
m Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
1))
          in  (IpBlock Canonical, IpBlock Canonical)
-> Maybe (IpBlock Canonical, IpBlock Canonical)
forall a. a -> Maybe a
Just
              ( IpAddress -> IpNetMask -> IpBlock Canonical
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress  Word32
b     ) IpNetMask
halfMask
              , IpAddress -> IpNetMask -> IpBlock Canonical
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress (Word32
b Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
c)) IpNetMask
halfMask
              )
    else  Maybe (IpBlock Canonical, IpBlock Canonical)
forall a. Maybe a
Nothing

showsIpAddress :: IpAddress -> String -> String
showsIpAddress :: IpAddress -> ShowS
showsIpAddress (IpAddress Word32
w) =
  Word32 -> ShowS
forall a. Show a => a -> ShowS
shows ((Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
24) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.&. Word32
0xff) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
'.'Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  Word32 -> ShowS
forall a. Show a => a -> ShowS
shows ((Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
16) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.&. Word32
0xff) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
'.'Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  Word32 -> ShowS
forall a. Show a => a -> ShowS
shows ((Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>.  Count
8) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.&. Word32
0xff) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
'.'Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  Word32 -> ShowS
forall a. Show a => a -> ShowS
shows ( Word32
w         Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.&. Word32
0xff)

showIpAddress :: IpAddress -> String
showIpAddress :: IpAddress -> String
showIpAddress IpAddress
ipAddress = IpAddress -> ShowS
showsIpAddress IpAddress
ipAddress String
""

tshowIpAddress :: IpAddress -> T.Text
tshowIpAddress :: IpAddress -> Text
tshowIpAddress = String -> Text
T.pack (String -> Text) -> (IpAddress -> String) -> IpAddress -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IpAddress -> String
showIpAddress

showsIpBlock :: IpBlock v -> String -> String
showsIpBlock :: IpBlock v -> ShowS
showsIpBlock (IpBlock IpAddress
b (IpNetMask Word8
m)) = IpAddress -> ShowS
forall a. Show a => a -> ShowS
shows IpAddress
b ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char
'/'Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> ShowS
forall a. Show a => a -> ShowS
shows Word8
m

showIpBlock :: IpBlock v -> String
showIpBlock :: IpBlock v -> String
showIpBlock IpBlock v
ipBlock = IpBlock v -> ShowS
forall v. IpBlock v -> ShowS
showsIpBlock IpBlock v
ipBlock String
""

tshowIpBlock :: IpBlock v -> T.Text
tshowIpBlock :: IpBlock v -> Text
tshowIpBlock = String -> Text
T.pack (String -> Text) -> (IpBlock v -> String) -> IpBlock v -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IpBlock v -> String
forall v. IpBlock v -> String
showIpBlock

wordsToIpAddress :: Word8 -> Word8 -> Word8 -> Word8 -> IpAddress
wordsToIpAddress :: Word8 -> Word8 -> Word8 -> Word8 -> IpAddress
wordsToIpAddress Word8
a Word8
b Word8
c Word8
d = Word32 -> IpAddress
IpAddress (Word32 -> IpAddress) -> Word32 -> IpAddress
forall a b. (a -> b) -> a -> b
$
  ( Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
a Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Count
24) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.|.
  ( Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
b Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Count
16) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.|.
  ( Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
c Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<.  Count
8) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.|.
    Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
d

ipAddressToWords :: IpAddress -> (Word8, Word8, Word8, Word8)
ipAddressToWords :: IpAddress -> (Word8, Word8, Word8, Word8)
ipAddressToWords (IpAddress Word32
w) =
  ( Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
24) Word8 -> Word8 -> Word8
forall a. BitWise a => a -> a -> a
.&. Word8
0xff
  , Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
16) Word8 -> Word8 -> Word8
forall a. BitWise a => a -> a -> a
.&. Word8
0xff
  , Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>.  Count
8) Word8 -> Word8 -> Word8
forall a. BitWise a => a -> a -> a
.&. Word8
0xff
  , Word32 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
w         Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.&. Word32
0xff)
  )

parseIpAddress :: AP.Parser IpAddress
parseIpAddress :: Parser IpAddress
parseIpAddress = Word32 -> IpAddress
IpAddress (Word32 -> IpAddress) -> MkParser String Word32 -> Parser IpAddress
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MkParser String Word32
I.ipv4Address

parseIpAddressAsBlock :: AP.Parser (IpBlock v)
parseIpAddressAsBlock :: Parser (IpBlock v)
parseIpAddressAsBlock = (\IpAddress
addr -> IpAddress -> IpNetMask -> IpBlock v
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock IpAddress
addr (Word8 -> IpNetMask
IpNetMask Word8
32)) (IpAddress -> IpBlock v) -> Parser IpAddress -> Parser (IpBlock v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser IpAddress
parseIpAddress

parseUnalignedIpBlock :: AP.Parser (IpBlock Unaligned)
parseUnalignedIpBlock :: Parser (IpBlock Unaligned)
parseUnalignedIpBlock = do
  (Word32
a, Word8
m) <- Parser (Word32, Word8)
I.ipv4Block
  IpBlock Unaligned -> Parser (IpBlock Unaligned)
forall (m :: * -> *) a. Monad m => a -> m a
return (IpAddress -> IpNetMask -> IpBlock Unaligned
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress Word32
a) (Word8 -> IpNetMask
IpNetMask Word8
m))

parseCanonicalIpBlock :: AP.Parser (IpBlock Canonical)
parseCanonicalIpBlock :: Parser (IpBlock Canonical)
parseCanonicalIpBlock = do
  IpBlock Unaligned
b <- Parser (IpBlock Unaligned)
parseUnalignedIpBlock
  if IpBlock Unaligned -> Bool
forall v. IpBlock v -> Bool
isCanonical IpBlock Unaligned
b
    then let IpBlock IpAddress
ip IpNetMask
m = IpBlock Unaligned
b in IpBlock Canonical -> Parser (IpBlock Canonical)
forall (m :: * -> *) a. Monad m => a -> m a
return (IpAddress -> IpNetMask -> IpBlock Canonical
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock IpAddress
ip IpNetMask
m)
    else String -> Parser (IpBlock Canonical)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser (IpBlock Canonical))
-> String -> Parser (IpBlock Canonical)
forall a b. (a -> b) -> a -> b
$ IpBlock Unaligned -> String
forall v. IpBlock v -> String
showIpBlock IpBlock Unaligned
b String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" is not a canonical block"

splitIpRange :: Range IpAddress -> (IpBlock Canonical, Maybe (Range IpAddress))
splitIpRange :: Range IpAddress -> (IpBlock Canonical, Maybe (Range IpAddress))
splitIpRange (Range (IpAddress Word32
a) (IpAddress Word32
z)) = (IpBlock Canonical
forall v. IpBlock v
block, Maybe (Range IpAddress)
remainder)
  where bpOuter :: Int
bpOuter   = Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
- Word32 -> Int
forall b. FiniteBits b => b -> Int
B.countLeadingZeros (Word32
z Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1 Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
- Word32
a) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
        bpInner :: Int
bpInner   = Word32 -> Int
forall b. FiniteBits b => b -> Int
B.countTrailingZeros ((Word32
forall a. Bounded a => a
maxBound Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. (Int -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
bpOuter Count -> Count -> Count
forall a. BitWise a => a -> a -> a
.&. Count
0x7f)) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.|. Word32
a)
        block :: IpBlock v
block     = IpAddress -> IpNetMask -> IpBlock v
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress Word32
a) (Word8 -> IpNetMask
IpNetMask (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
width Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
bpInner)))
        hostMask :: Word32
hostMask  = Word32 -> Word32
forall a. BitWise a => a -> a
comp (Word32
forall a. Bounded a => a
maxBound Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Int -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
bpInner)
        remainder :: Maybe (Range IpAddress)
remainder = if Word32
a Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
hostMask Word32 -> Word32 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word32
z
          then Maybe (Range IpAddress)
forall a. Maybe a
Nothing
          else Range IpAddress -> Maybe (Range IpAddress)
forall a. a -> Maybe a
Just (IpAddress -> IpAddress -> Range IpAddress
forall a. a -> a -> Range a
Range (Word32 -> IpAddress
IpAddress (Word32
a Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
hostMask Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32
1)) (Word32 -> IpAddress
IpAddress Word32
z))
        width :: Int
width = Word32 -> Int
forall b. FiniteBits b => b -> Int
B.finiteBitSize Word32
a

-- | Assume distinct & sorted input
collapseIpBlocks :: [IpBlock Canonical] -> [IpBlock Canonical]
collapseIpBlocks :: [IpBlock Canonical] -> [IpBlock Canonical]
collapseIpBlocks [IpBlock Canonical]
tomerge =
  [IpBlock Canonical] -> [IpBlock Canonical]
forall v. [IpBlock v] -> [IpBlock v]
skipOverlapped ([IpBlock Canonical] -> [IpBlock Canonical])
-> [IpBlock Canonical] -> [IpBlock Canonical]
forall a b. (a -> b) -> a -> b
$ [[IpBlock Canonical]] -> [IpBlock Canonical]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[IpBlock Canonical]] -> [IpBlock Canonical])
-> [[IpBlock Canonical]] -> [IpBlock Canonical]
forall a b. (a -> b) -> a -> b
$ Seq (IpBlock Canonical) -> [IpBlock Canonical]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Seq (IpBlock Canonical) -> [IpBlock Canonical])
-> [Seq (IpBlock Canonical)] -> [[IpBlock Canonical]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go Seq (IpBlock Canonical)
forall a. Seq a
S.empty [IpBlock Canonical]
tomerge
  where
    go :: S.Seq (IpBlock Canonical) -> [IpBlock Canonical] -> [S.Seq (IpBlock Canonical)]
    go :: Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go Seq (IpBlock Canonical)
m [] = [Seq (IpBlock Canonical)
m]
    go Seq (IpBlock Canonical)
m (IpBlock Canonical
b:[IpBlock Canonical]
bs) =
      case Seq (IpBlock Canonical) -> ViewR (IpBlock Canonical)
forall a. Seq a -> ViewR a
S.viewr Seq (IpBlock Canonical)
m of
        ViewR (IpBlock Canonical)
S.EmptyR -> Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go (Seq (IpBlock Canonical)
m Seq (IpBlock Canonical)
-> IpBlock Canonical -> Seq (IpBlock Canonical)
forall a. Seq a -> a -> Seq a
S.|> IpBlock Canonical
b) [IpBlock Canonical]
bs
        Seq (IpBlock Canonical)
m' S.:> IpBlock Canonical
bp -> do
          let sp :: IpBlock v
sp@(IpBlock IpAddress
_ (IpNetMask Word8
msk)) = IpBlock Canonical -> IpBlock v
forall v v. IpBlock v -> IpBlock v
superBlock IpBlock Canonical
bp
          let sp' :: IpBlock v
sp'@(IpBlock IpAddress
_ (IpNetMask Word8
msk')) = IpBlock Canonical -> IpBlock v
forall v v. IpBlock v -> IpBlock v
superBlock IpBlock Canonical
b
          if IpBlock Any
forall v. IpBlock v
sp IpBlock Any -> IpBlock Any -> Bool
forall a. Eq a => a -> a -> Bool
== IpBlock Any
forall v. IpBlock v
sp' then Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go Seq (IpBlock Canonical)
m' (IpBlock Canonical
forall v. IpBlock v
sp IpBlock Canonical -> [IpBlock Canonical] -> [IpBlock Canonical]
forall a. a -> [a] -> [a]
: [IpBlock Canonical]
bs)
          else if Word8
msk Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> Word8
msk' then
                 Seq (IpBlock Canonical)
m Seq (IpBlock Canonical)
-> [Seq (IpBlock Canonical)] -> [Seq (IpBlock Canonical)]
forall a. a -> [a] -> [a]
: Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go (Seq (IpBlock Canonical)
forall a. Seq a
S.empty Seq (IpBlock Canonical)
-> IpBlock Canonical -> Seq (IpBlock Canonical)
forall a. Seq a -> a -> Seq a
S.|> IpBlock Canonical
b) [IpBlock Canonical]
bs
               else
                 Seq (IpBlock Canonical)
-> [IpBlock Canonical] -> [Seq (IpBlock Canonical)]
go (Seq (IpBlock Canonical)
m Seq (IpBlock Canonical)
-> IpBlock Canonical -> Seq (IpBlock Canonical)
forall a. Seq a -> a -> Seq a
S.|> IpBlock Canonical
b) [IpBlock Canonical]
bs
    superBlock :: IpBlock v -> IpBlock v
superBlock (IpBlock (IpAddress Word32
w32) (IpNetMask Word8
m)) =
      IpAddress -> IpNetMask -> IpBlock v
forall v. IpAddress -> IpNetMask -> IpBlock v
IpBlock (Word32 -> IpAddress
IpAddress (Word32
w32 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
B..&. (Word32
0xFFFFFFFF Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`B.shiftL` Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
32 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- (Word8
m Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
1))))) (Word8 -> IpNetMask
IpNetMask (Word8
m Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
1))
    skipOverlapped :: [IpBlock v] -> [IpBlock v]
skipOverlapped [] = []
    skipOverlapped [IpBlock v
b] = [IpBlock v
b]
    skipOverlapped (IpBlock v
b1:IpBlock v
b2:[IpBlock v]
bs) =
      if IpBlock v -> IpAddress
forall v. IpBlock v -> IpAddress
lastIpAddress IpBlock v
b1 IpAddress -> IpAddress -> Bool
forall a. Ord a => a -> a -> Bool
>= IpBlock v -> IpAddress
forall v. IpBlock v -> IpAddress
lastIpAddress IpBlock v
b2 then
        [IpBlock v] -> [IpBlock v]
skipOverlapped (IpBlock v
b1IpBlock v -> [IpBlock v] -> [IpBlock v]
forall a. a -> [a] -> [a]
:[IpBlock v]
bs)
      else
        IpBlock v
b1 IpBlock v -> [IpBlock v] -> [IpBlock v]
forall a. a -> [a] -> [a]
: [IpBlock v] -> [IpBlock v]
skipOverlapped (IpBlock v
b2IpBlock v -> [IpBlock v] -> [IpBlock v]
forall a. a -> [a] -> [a]
:[IpBlock v]
bs)

rangeToBlocksDL :: Range IpAddress -> [IpBlock Canonical] -> [IpBlock Canonical]
rangeToBlocksDL :: Range IpAddress -> [IpBlock Canonical] -> [IpBlock Canonical]
rangeToBlocksDL Range IpAddress
r = do
  let (IpBlock Canonical
b, Maybe (Range IpAddress)
remainder) = Range IpAddress -> (IpBlock Canonical, Maybe (Range IpAddress))
splitIpRange Range IpAddress
r
  case Maybe (Range IpAddress)
remainder of
    Just Range IpAddress
rmd -> (IpBlock Canonical
bIpBlock Canonical -> [IpBlock Canonical] -> [IpBlock Canonical]
forall a. a -> [a] -> [a]
:) ([IpBlock Canonical] -> [IpBlock Canonical])
-> ([IpBlock Canonical] -> [IpBlock Canonical])
-> [IpBlock Canonical]
-> [IpBlock Canonical]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Range IpAddress -> [IpBlock Canonical] -> [IpBlock Canonical]
rangeToBlocksDL Range IpAddress
rmd
    Maybe (Range IpAddress)
Nothing  -> (IpBlock Canonical
bIpBlock Canonical -> [IpBlock Canonical] -> [IpBlock Canonical]
forall a. a -> [a] -> [a]
:)

rangeToBlocks :: Range IpAddress -> [IpBlock Canonical]
rangeToBlocks :: Range IpAddress -> [IpBlock Canonical]
rangeToBlocks Range IpAddress
r = Range IpAddress -> [IpBlock Canonical] -> [IpBlock Canonical]
rangeToBlocksDL Range IpAddress
r []

blockToRange :: IpBlock Canonical -> Range IpAddress
blockToRange :: IpBlock Canonical -> Range IpAddress
blockToRange IpBlock Canonical
b = (IpAddress -> IpAddress -> Range IpAddress)
-> (IpAddress, IpAddress) -> Range IpAddress
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry IpAddress -> IpAddress -> Range IpAddress
forall a. a -> a -> Range a
Range ((IpAddress, IpAddress) -> Range IpAddress)
-> (IpAddress, IpAddress) -> Range IpAddress
forall a b. (a -> b) -> a -> b
$ (IpBlock Canonical -> IpAddress)
-> (IpBlock Canonical -> IpAddress)
-> (IpBlock Canonical, IpBlock Canonical)
-> (IpAddress, IpAddress)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap IpBlock Canonical -> IpAddress
forall v. IpBlock v -> IpAddress
firstIpAddress IpBlock Canonical -> IpAddress
forall v. IpBlock v -> IpAddress
lastIpAddress (IpBlock Canonical
b, IpBlock Canonical
b)

instance Contains (IpBlock a) where
  contains :: IpBlock a -> IpBlock a -> Bool
contains IpBlock a
l IpBlock a
r = IpBlock a -> IpAddress
forall v. IpBlock v -> IpAddress
firstIpAddress IpBlock a
l IpAddress -> IpAddress -> Bool
forall a. Ord a => a -> a -> Bool
<= IpBlock a -> IpAddress
forall v. IpBlock v -> IpAddress
firstIpAddress IpBlock a
r Bool -> Bool -> Bool
&& IpBlock a -> IpAddress
forall v. IpBlock v -> IpAddress
lastIpAddress IpBlock a
l IpAddress -> IpAddress -> Bool
forall a. Ord a => a -> a -> Bool
>= IpBlock a -> IpAddress
forall v. IpBlock v -> IpAddress
lastIpAddress IpBlock a
r