{-|
Module      : Net.DNSBase.RData.A
Description : Address records (A and AAAA)
Copyright   : (c) Viktor Dukhovni, 2026
License     : BSD-3-Clause
Maintainer  : ietf-dane@dukhovni.org
Stability   : unstable

The two address RR types parallel the variants of 'Data.IP.IP':
'T_a' wraps the @A@ RR's 'IPv4' payload, 'T_aaaa' wraps the
@AAAA@ RR's 'IPv6' payload.  Construct or destructure via the
@T_A@ / @T_AAAA@ pattern constructors.  When working with a
polymorphic 'RData' value that may be either, 'evalIP'
dispatches on whichever applies and lifts the address into the
common 'Data.IP.IP' sum.
-}

module Net.DNSBase.RData.A
    ( T_a(..)
    , T_aaaa(..)
    , evalIP
    ) where
import Data.IP (IP(..), IPv4, IPv6)

import Net.DNSBase.Decode.State
import Net.DNSBase.Encode.State
import Net.DNSBase.Present
import Net.DNSBase.RData
import Net.DNSBase.RRTYPE
import Net.DNSBase.Internal.Util (showsP)

-- | The @A@ resource record
-- ([RFC 1035 section 3.4.1](https://tools.ietf.org/html/rfc1035#section-3.4.1))
-- — a 32-bit IPv4 address transmitted as four bytes in network
-- order.  The derived 'Ord' is numeric 'IPv4' order, which agrees
-- with canonical RR-content ordering
-- ([RFC 4034 section 6.2](https://datatracker.ietf.org/doc/html/rfc4034#section-6.2)).
--
-- See 'T_aaaa' for the IPv6-family parallel, and 'evalIP' for a
-- helper that handles either uniformly.
newtype T_a = T_A IPv4 -- ^ 'IPv4' address
    deriving (T_a -> T_a -> Bool
(T_a -> T_a -> Bool) -> (T_a -> T_a -> Bool) -> Eq T_a
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: T_a -> T_a -> Bool
== :: T_a -> T_a -> Bool
$c/= :: T_a -> T_a -> Bool
/= :: T_a -> T_a -> Bool
Eq, Eq T_a
Eq T_a =>
(T_a -> T_a -> Ordering)
-> (T_a -> T_a -> Bool)
-> (T_a -> T_a -> Bool)
-> (T_a -> T_a -> Bool)
-> (T_a -> T_a -> Bool)
-> (T_a -> T_a -> T_a)
-> (T_a -> T_a -> T_a)
-> Ord T_a
T_a -> T_a -> Bool
T_a -> T_a -> Ordering
T_a -> T_a -> T_a
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
$ccompare :: T_a -> T_a -> Ordering
compare :: T_a -> T_a -> Ordering
$c< :: T_a -> T_a -> Bool
< :: T_a -> T_a -> Bool
$c<= :: T_a -> T_a -> Bool
<= :: T_a -> T_a -> Bool
$c> :: T_a -> T_a -> Bool
> :: T_a -> T_a -> Bool
$c>= :: T_a -> T_a -> Bool
>= :: T_a -> T_a -> Bool
$cmax :: T_a -> T_a -> T_a
max :: T_a -> T_a -> T_a
$cmin :: T_a -> T_a -> T_a
min :: T_a -> T_a -> T_a
Ord, Int -> T_a
T_a -> Int
T_a -> [T_a]
T_a -> T_a
T_a -> T_a -> [T_a]
T_a -> T_a -> T_a -> [T_a]
(T_a -> T_a)
-> (T_a -> T_a)
-> (Int -> T_a)
-> (T_a -> Int)
-> (T_a -> [T_a])
-> (T_a -> T_a -> [T_a])
-> (T_a -> T_a -> [T_a])
-> (T_a -> T_a -> T_a -> [T_a])
-> Enum T_a
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: T_a -> T_a
succ :: T_a -> T_a
$cpred :: T_a -> T_a
pred :: T_a -> T_a
$ctoEnum :: Int -> T_a
toEnum :: Int -> T_a
$cfromEnum :: T_a -> Int
fromEnum :: T_a -> Int
$cenumFrom :: T_a -> [T_a]
enumFrom :: T_a -> [T_a]
$cenumFromThen :: T_a -> T_a -> [T_a]
enumFromThen :: T_a -> T_a -> [T_a]
$cenumFromTo :: T_a -> T_a -> [T_a]
enumFromTo :: T_a -> T_a -> [T_a]
$cenumFromThenTo :: T_a -> T_a -> T_a -> [T_a]
enumFromThenTo :: T_a -> T_a -> T_a -> [T_a]
Enum)

instance Show T_a where
    showsPrec :: Int -> T_a -> ShowS
showsPrec Int
p (T_A IPv4
a) = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
        String -> ShowS
showString String
"T_A \"" ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IPv4 -> ShowS
forall a. Show a => a -> ShowS
shows IPv4
a ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
'"'

instance Presentable T_a where
    present :: T_a -> Builder -> Builder
present (T_A IPv4
a) = IPv4 -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present IPv4
a

instance KnownRData T_a where
    rdType :: forall b -> (b ~ T_a) => RRTYPE
rdType _ = RRTYPE
A
    {-# INLINE rdType #-}
    rdEncode :: forall s. T_a -> SPut s RData
rdEncode (T_A IPv4
ip4) = IPv4 -> SPut s RData
forall r s. ErrorContext r => IPv4 -> SPut s r
putIPv4 IPv4
ip4
    rdDecode :: forall b -> (b ~ T_a) => RDataExtensionVal T_a -> Int -> SGet RData
rdDecode _ RDataExtensionVal T_a
_ = SGet RData -> Int -> SGet RData
forall a b. a -> b -> a
const do T_a -> RData
forall a. KnownRData a => a -> RData
RData (T_a -> RData) -> (IPv4 -> T_a) -> IPv4 -> RData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IPv4 -> T_a
T_A (IPv4 -> RData) -> SGet IPv4 -> SGet RData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SGet IPv4
getIPv4


-- | The @AAAA@ resource record
-- ([RFC 3596 section 2.1](https://tools.ietf.org/html/rfc3596#section-2.1))
-- — a 128-bit IPv6 address transmitted as sixteen bytes in network
-- order.  The derived 'Ord' is numeric 'IPv6' order, which agrees
-- with canonical RR-content ordering
-- ([RFC 4034 section 6.2](https://datatracker.ietf.org/doc/html/rfc4034#section-6.2)).
--
-- See 'T_a' for the IPv4-family parallel, and 'evalIP' for a
-- helper that handles either uniformly.
newtype T_aaaa = T_AAAA IPv6 -- ^ 'IPv6' address
    deriving (T_aaaa -> T_aaaa -> Bool
(T_aaaa -> T_aaaa -> Bool)
-> (T_aaaa -> T_aaaa -> Bool) -> Eq T_aaaa
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: T_aaaa -> T_aaaa -> Bool
== :: T_aaaa -> T_aaaa -> Bool
$c/= :: T_aaaa -> T_aaaa -> Bool
/= :: T_aaaa -> T_aaaa -> Bool
Eq, Eq T_aaaa
Eq T_aaaa =>
(T_aaaa -> T_aaaa -> Ordering)
-> (T_aaaa -> T_aaaa -> Bool)
-> (T_aaaa -> T_aaaa -> Bool)
-> (T_aaaa -> T_aaaa -> Bool)
-> (T_aaaa -> T_aaaa -> Bool)
-> (T_aaaa -> T_aaaa -> T_aaaa)
-> (T_aaaa -> T_aaaa -> T_aaaa)
-> Ord T_aaaa
T_aaaa -> T_aaaa -> Bool
T_aaaa -> T_aaaa -> Ordering
T_aaaa -> T_aaaa -> T_aaaa
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
$ccompare :: T_aaaa -> T_aaaa -> Ordering
compare :: T_aaaa -> T_aaaa -> Ordering
$c< :: T_aaaa -> T_aaaa -> Bool
< :: T_aaaa -> T_aaaa -> Bool
$c<= :: T_aaaa -> T_aaaa -> Bool
<= :: T_aaaa -> T_aaaa -> Bool
$c> :: T_aaaa -> T_aaaa -> Bool
> :: T_aaaa -> T_aaaa -> Bool
$c>= :: T_aaaa -> T_aaaa -> Bool
>= :: T_aaaa -> T_aaaa -> Bool
$cmax :: T_aaaa -> T_aaaa -> T_aaaa
max :: T_aaaa -> T_aaaa -> T_aaaa
$cmin :: T_aaaa -> T_aaaa -> T_aaaa
min :: T_aaaa -> T_aaaa -> T_aaaa
Ord)

instance Show T_aaaa where
    showsPrec :: Int -> T_aaaa -> ShowS
showsPrec Int
p (T_AAAA IPv6
a) = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
        String -> ShowS
showString String
"T_AAAA \"" ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IPv6 -> ShowS
forall a. Show a => a -> ShowS
shows IPv6
a ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
'"'

instance Presentable T_aaaa where
    present :: T_aaaa -> Builder -> Builder
present (T_AAAA IPv6
a) = IPv6 -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present IPv6
a

instance KnownRData T_aaaa where
    rdType :: forall b -> (b ~ T_aaaa) => RRTYPE
rdType _ = RRTYPE
AAAA
    {-# INLINE rdType #-}
    rdEncode :: forall s. T_aaaa -> SPut s RData
rdEncode (T_AAAA IPv6
ip6) = IPv6 -> SPut s RData
forall r s. ErrorContext r => IPv6 -> SPut s r
putIPv6 IPv6
ip6
    rdDecode :: forall b ->
(b ~ T_aaaa) => RDataExtensionVal T_aaaa -> Int -> SGet RData
rdDecode _ RDataExtensionVal T_aaaa
_ = SGet RData -> Int -> SGet RData
forall a b. a -> b -> a
const do T_aaaa -> RData
forall a. KnownRData a => a -> RData
RData (T_aaaa -> RData) -> (IPv6 -> T_aaaa) -> IPv6 -> RData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IPv6 -> T_aaaa
T_AAAA (IPv6 -> RData) -> SGet IPv6 -> SGet RData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SGet IPv6
getIPv6


-- | Apply the supplied function to whichever IP address an 'RData'
-- carries, lifting the 'T_a' or 'T_aaaa' payload into the unified
-- 'Data.IP.IP' sum.  Returns 'Nothing' for 'RData' of any other type.
--
-- > evalIP id (RData (T_A    ip)) == Just (IPv4 ip)
-- > evalIP id (RData (T_AAAA ip)) == Just (IPv6 ip)
evalIP :: (IP -> a) -> RData -> Maybe a
evalIP :: forall a. (IP -> a) -> RData -> Maybe a
evalIP IP -> a
f (RData -> Maybe T_a
forall a. KnownRData a => RData -> Maybe a
fromRData -> Just (T_A IPv4
ip))    = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$! IP -> a
f (IPv4 -> IP
IPv4 IPv4
ip)
evalIP IP -> a
f (RData -> Maybe T_aaaa
forall a. KnownRData a => RData -> Maybe a
fromRData -> Just (T_AAAA IPv6
ip)) = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$! IP -> a
f (IPv6 -> IP
IPv6 IPv6
ip)
evalIP IP -> a
_ RData
_                               = Maybe a
forall a. Maybe a
Nothing