-- |
-- Module      : Net.DNSBase.Internal.RR
-- Description : TBD
-- Copyright   : (c) Viktor Dukhovni, 2026
-- License     : BSD-3-Clause
-- Maintainer  : ietf-dane@dukhovni.org
-- Stability   : unstable
{-# LANGUAGE RecordWildCards #-}

module Net.DNSBase.Internal.RR
    ( RR(..)
    , putRR
    , rrDataCast
    , rrType
    ) where

import Net.DNSBase.Encode.Internal.Metric
import Net.DNSBase.Encode.Internal.State
import Net.DNSBase.Internal.Domain (Domain, equalWireHost)
import Net.DNSBase.Internal.Present
import Net.DNSBase.Internal.RData
import Net.DNSBase.Internal.RRTYPE
import Net.DNSBase.Internal.RRCLASS
import Net.DNSBase.Internal.Util

-- | DNS Resource Record [RFC1035 3.2.1](https://tools.ietf.org/html/rfc1035#section-3.2.1)
--
-- >                                 1  1  1  1  1  1
-- >   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-- > |                                               |
-- > /                                               /
-- > /                      NAME                     /
-- > |                                               |
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-- > |                      TYPE                     |
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-- > |                     CLASS                     |
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-- > |                      TTL                      |
-- > |                                               |
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
-- > |                   RDLENGTH                    |
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
-- > /                     RDATA                     /
-- > /                                               /
-- > +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
--
-- The @TYPE@ field is implicit in the polymorphic 'rrData'.
--
data RR = RR
    { RR -> Domain
rrOwner :: Domain
    , RR -> RRCLASS
rrClass :: RRCLASS
    , RR -> Word32
rrTTL   :: Word32
    , RR -> RData
rrData  :: RData
    } deriving (Int -> RR -> ShowS
[RR] -> ShowS
RR -> String
(Int -> RR -> ShowS)
-> (RR -> String) -> ([RR] -> ShowS) -> Show RR
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RR -> ShowS
showsPrec :: Int -> RR -> ShowS
$cshow :: RR -> String
show :: RR -> String
$cshowList :: [RR] -> ShowS
showList :: [RR] -> ShowS
Show)

instance Eq RR where
    RR
a == :: RR -> RR -> Bool
== RR
b = RR -> Domain
rrOwner RR
a Domain -> Domain -> Bool
`equalWireHost` RR -> Domain
rrOwner RR
b
          Bool -> Bool -> Bool
&& RR -> RRCLASS
rrClass RR
a RRCLASS -> RRCLASS -> Bool
forall a. Eq a => a -> a -> Bool
==              RR -> RRCLASS
rrClass RR
b
          Bool -> Bool -> Bool
&& RR -> Word32
rrTTL   RR
a Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
==              RR -> Word32
rrTTL   RR
b
          Bool -> Bool -> Bool
&& RR -> RData
rrData  RR
a RData -> RData -> Bool
forall a. Eq a => a -> a -> Bool
==              RR -> RData
rrData  RR
b

instance Presentable RR where
    present :: RR -> Builder -> Builder
present RR{Word32
RRCLASS
Domain
RData
rrData :: RR -> RData
rrOwner :: RR -> Domain
rrClass :: RR -> RRCLASS
rrTTL :: RR -> Word32
rrOwner :: Domain
rrClass :: RRCLASS
rrTTL :: Word32
rrData :: RData
..} =
        Domain -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present Domain
rrOwner
        (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word32 -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp Word32
rrTTL
        (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RRCLASS -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp RRCLASS
rrClass
        (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RData -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp RData
rrData

putRR :: RR -> SPut s RData
putRR :: forall s. RR -> SPut s RData
putRR RR{Word32
RRCLASS
Domain
RData
rrData :: RR -> RData
rrOwner :: RR -> Domain
rrClass :: RR -> RRCLASS
rrTTL :: RR -> Word32
rrOwner :: Domain
rrClass :: RRCLASS
rrTTL :: Word32
rrData :: RData
..} = do
    Domain -> SPut s RData
forall r s. ErrorContext r => Domain -> SPut s r
putDomain Domain
rrOwner
    SizedBuilder -> SPut s RData
forall r s. ErrorContext r => SizedBuilder -> SPut s r
putSizedBuilder (SizedBuilder -> SPut s RData) -> SizedBuilder -> SPut s RData
forall a b. (a -> b) -> a -> b
$!
        Word16 -> SizedBuilder
mbWord16 (RRTYPE -> Word16
forall a b. Coercible a b => a -> b
coerce (RRTYPE -> Word16) -> RRTYPE -> Word16
forall a b. (a -> b) -> a -> b
$ RData -> RRTYPE
rdataType RData
rrData)
        SizedBuilder -> SizedBuilder -> SizedBuilder
forall a. Semigroup a => a -> a -> a
<> Word16 -> SizedBuilder
mbWord16 (RRCLASS -> Word16
forall a b. Coercible a b => a -> b
coerce RRCLASS
rrClass)
        SizedBuilder -> SizedBuilder -> SizedBuilder
forall a. Semigroup a => a -> a -> a
<> Word32 -> SizedBuilder
mbWord32 Word32
rrTTL
    SPut s RData -> SPut s RData
forall r s a. ErrorContext r => SPutM s r a -> SPutM s r a
passLen (SPut s RData -> SPut s RData) -> SPut s RData -> SPut s RData
forall a b. (a -> b) -> a -> b
$ RData -> SPut s RData
forall s. RData -> SPut s RData
rdataEncode RData
rrData

-- | Attempt to cast the 'RData' payload of an 'RR' to a
-- 'KnownRData' type, obtaining its type-specific representation.
-- Returns 'Nothing' if the types do not match.
--
-- Note that /opaque/ 'RData' payloads can't be cast directly to
-- type-specific forms, instead their content has to be explicitly
-- decoded (see 'Net.DNSBase.RData.fromOpaque').
rrDataCast :: KnownRData a => RR -> Maybe a
rrDataCast :: forall a. KnownRData a => RR -> Maybe a
rrDataCast = RData -> Maybe a
forall a. KnownRData a => RData -> Maybe a
fromRData (RData -> Maybe a) -> (RR -> RData) -> RR -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RR -> RData
rrData
{-# INLINE rrDataCast #-}

-- | Returns the 'RRTYPE' of the 'RData' payload of the 'RR'.
rrType :: RR -> RRTYPE
rrType :: RR -> RRTYPE
rrType = RData -> RRTYPE
rdataType (RData -> RRTYPE) -> (RR -> RData) -> RR -> RRTYPE
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RR -> RData
rrData