packages feed

dnsbase-1.0.0.0: internal/Net/DNSBase/EDNS/Internal/Option/Opaque.hs

-- |
-- Module      : Net.DNSBase.EDNS.Internal.Option.Opaque
-- Description : Internal: fallback wrapper for unrecognised EDNS options
-- Copyright   : (c) Viktor Dukhovni, 2026
-- License     : BSD-3-Clause
-- Maintainer  : ietf-dane@dukhovni.org
-- Stability   : unstable
module Net.DNSBase.EDNS.Internal.Option.Opaque
    ( OpaqueOption(..)
    , opaqueEdnsOption
    )
    where

import Net.DNSBase.Decode.Internal.State
import Net.DNSBase.EDNS.Internal.OptNum
import Net.DNSBase.EDNS.Internal.Option
import Net.DNSBase.Encode.Internal.State
import Net.DNSBase.Internal.Bytes
import Net.DNSBase.Internal.Nat16
import Net.DNSBase.Internal.Present
import Net.DNSBase.Internal.Util

-- | Unrecognized EDNS Option whose contents are treated as an opaque octet-string
-- and are left unparsed. The OPTION-CODE is encoded as a type-level natural, so
-- opaque options with different option code values are of different types.
type OpaqueOption :: Nat -> Type
data OpaqueOption n = OpaqueOption ShortByteString

deriving instance Eq (OpaqueOption n)

instance Nat16 n => Show (OpaqueOption n) where
    showsPrec p (OpaqueOption bs) = showsP p $
        showString "OpaqueOption @" . shows (natToWord16 n) . showChar ' '
        . shows @Bytes16 (coerce bs)

instance Presentable (OpaqueOption n) where
    present = \ (OpaqueOption bs) -> present @Bytes16 (coerce bs)

instance Nat16 n => KnownEdnsOption (OpaqueOption n) where
    optNum _ = OptNum $ natToWord16 n
    {-# INLINE optNum #-}
    optPres _ = present "OPT" . present (natToWord16 n)
    optEncode (OpaqueOption bs) = putShortByteString $ coerce bs
    optDecode _ _ = EdnsOption . OpaqueOption @n <.> getShortNByteString

-- | Create opaque option from its opcode and Bytes16 value
opaqueEdnsOption :: Word16 -> ShortByteString -> EdnsOption
opaqueEdnsOption w bs = withNat16 w go
  where
    go :: forall (n :: Nat) -> Nat16 n => EdnsOption
    go n = EdnsOption $ OpaqueOption @n bs