{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
module Net.DNSBase.EDNS.Internal.Option
(
KnownEdnsOption(..)
, EdnsOption(..)
, fromOption
, monoOption
, optionCode
, putOption
, OptionCtl
, optCtlSet
, optCtlAdd
, emptyOptionCtl
, applyOptionCtl
, OptionCodec(..)
) where
import Data.List (sortOn)
import Net.DNSBase.Decode.Internal.State
import Net.DNSBase.EDNS.Internal.OptNum
import Net.DNSBase.Encode.Internal.State
import Net.DNSBase.Internal.Present
import Net.DNSBase.Internal.Util
class (Typeable a, Eq a, Show a, Presentable a) => KnownEdnsOption a where
type OptionExtensionVal a :: Type
type OptionExtensionVal a = ()
optionExtensionVal :: forall b -> b ~ a => OptionExtensionVal a
default optionExtensionVal :: (OptionExtensionVal a ~ ())
=> forall b -> b ~ a
=> OptionExtensionVal a
optionExtensionVal _ = ()
optNum :: forall b -> b ~ a => OptNum
optPres :: forall b -> b ~ a => Builder -> Builder
optEncode :: forall s r. (Typeable r, Eq r, Show r)
=> a
-> SPut s r
optDecode :: forall b
-> b ~ a
=> OptionExtensionVal b
-> Int
-> SGet EdnsOption
optPres t = OptNum -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present (OptNum -> Builder -> Builder) -> OptNum -> Builder -> Builder
forall a b. (a -> b) -> a -> b
$ optNum t
{-# INLINE optPres #-}
data OptionCodec where
OptionCodec :: KnownEdnsOption a
=> Proxy a
-> OptionExtensionVal a
-> OptionCodec
data EdnsOption = forall a. KnownEdnsOption a => EdnsOption a
fromOption :: forall a. KnownEdnsOption a => EdnsOption -> Maybe a
fromOption :: forall a. KnownEdnsOption a => EdnsOption -> Maybe a
fromOption (EdnsOption a
a) = a -> Maybe a
forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast a
a
{-# INLINE fromOption #-}
instance Show EdnsOption where
showsPrec :: Int -> EdnsOption -> ShowS
showsPrec Int
p (EdnsOption a
a) = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString String
"EdnsOption " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ShowS
forall a. Show a => a -> ShowS
shows' a
a
instance Presentable EdnsOption where
present :: EdnsOption -> Builder -> Builder
present (EdnsOption a
a) = a -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present a
a
{-# INLINE present #-}
instance Eq EdnsOption where
(EdnsOption (a
_a :: a)) == :: EdnsOption -> EdnsOption -> Bool
== (EdnsOption (a
_b :: b)) =
case teq a b of
Just a :~: a
Refl -> a
_a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
a
_b
Maybe (a :~: a)
_ -> Bool
False
optionCode :: EdnsOption -> OptNum
optionCode :: EdnsOption -> OptNum
optionCode (EdnsOption (a
_ :: a)) = optNum a
{-# INLINE optionCode #-}
monoOption :: forall a t. (KnownEdnsOption a, Foldable t) => t EdnsOption -> [a]
monoOption :: forall a (t :: * -> *).
(KnownEdnsOption a, Foldable t) =>
t EdnsOption -> [a]
monoOption = (EdnsOption -> [a] -> [a]) -> [a] -> t EdnsOption -> [a]
forall a b. (a -> b -> b) -> b -> t a -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (([a] -> [a]) -> (a -> [a] -> [a]) -> Maybe a -> [a] -> [a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [a] -> [a]
forall a. a -> a
id (:) (Maybe a -> [a] -> [a])
-> (EdnsOption -> Maybe a) -> EdnsOption -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EdnsOption -> Maybe a
forall a. KnownEdnsOption a => EdnsOption -> Maybe a
fromOption) []
{-# INLINE monoOption #-}
putOption :: forall s r. (Typeable r, Eq r, Show r)
=> EdnsOption -> SPut s r
putOption :: forall s r. (Typeable r, Eq r, Show r) => EdnsOption -> SPut s r
putOption (EdnsOption (a
o :: a)) = do
Word16 -> SPut s r
forall r s. ErrorContext r => Word16 -> SPut s r
put16 (Word16 -> SPut s r) -> Word16 -> SPut s r
forall a b. (a -> b) -> a -> b
$ OptNum -> Word16
forall a b. Coercible a b => a -> b
coerce (optNum a)
SPut s r -> SPut s r
forall r s a. ErrorContext r => SPutM s r a -> SPutM s r a
passLen (a -> SPut s r
forall a s r.
(KnownEdnsOption a, Typeable r, Eq r, Show r) =>
a -> SPut s r
forall s r. (Typeable r, Eq r, Show r) => a -> SPut s r
optEncode a
o)
{-# INLINE putOption #-}
newtype OptionCtl = OptionCtl { OptionCtl -> [EdnsOption]
fromOptionCtl :: [EdnsOption] }
deriving (OptionCtl -> OptionCtl -> Bool
(OptionCtl -> OptionCtl -> Bool)
-> (OptionCtl -> OptionCtl -> Bool) -> Eq OptionCtl
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OptionCtl -> OptionCtl -> Bool
== :: OptionCtl -> OptionCtl -> Bool
$c/= :: OptionCtl -> OptionCtl -> Bool
/= :: OptionCtl -> OptionCtl -> Bool
Eq, Int -> OptionCtl -> ShowS
[OptionCtl] -> ShowS
OptionCtl -> String
(Int -> OptionCtl -> ShowS)
-> (OptionCtl -> String)
-> ([OptionCtl] -> ShowS)
-> Show OptionCtl
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OptionCtl -> ShowS
showsPrec :: Int -> OptionCtl -> ShowS
$cshow :: OptionCtl -> String
show :: OptionCtl -> String
$cshowList :: [OptionCtl] -> ShowS
showList :: [OptionCtl] -> ShowS
Show)
optCtlSet :: [EdnsOption] -> OptionCtl -> OptionCtl
optCtlSet :: [EdnsOption] -> OptionCtl -> OptionCtl
optCtlSet [EdnsOption]
opts OptionCtl
_ = [EdnsOption] -> OptionCtl
OptionCtl ((EdnsOption -> OptNum) -> [EdnsOption] -> [EdnsOption]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn EdnsOption -> OptNum
optionCode [EdnsOption]
opts)
optCtlAdd :: [EdnsOption] -> OptionCtl -> OptionCtl
optCtlAdd :: [EdnsOption] -> OptionCtl -> OptionCtl
optCtlAdd [EdnsOption]
opts (OptionCtl [EdnsOption]
opts') = [EdnsOption] -> OptionCtl
OptionCtl ([EdnsOption] -> OptionCtl) -> [EdnsOption] -> OptionCtl
forall a b. (a -> b) -> a -> b
$ [EdnsOption] -> [EdnsOption] -> [EdnsOption]
lbMerge ((EdnsOption -> OptNum) -> [EdnsOption] -> [EdnsOption]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn EdnsOption -> OptNum
optionCode [EdnsOption]
opts) [EdnsOption]
opts'
where
lbMerge :: [EdnsOption] -> [EdnsOption] -> [EdnsOption]
lbMerge [] [EdnsOption]
ys = [EdnsOption]
ys
lbMerge [EdnsOption]
xs [] = [EdnsOption]
xs
lbMerge xs :: [EdnsOption]
xs@(EdnsOption
x:[EdnsOption]
xt) ys :: [EdnsOption]
ys@(EdnsOption
y:[EdnsOption]
yt) =
case OptNum -> OptNum -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (EdnsOption -> OptNum
optionCode EdnsOption
x) (EdnsOption -> OptNum
optionCode EdnsOption
y) of
Ordering
LT -> EdnsOption
x EdnsOption -> [EdnsOption] -> [EdnsOption]
forall a. a -> [a] -> [a]
: [EdnsOption] -> [EdnsOption] -> [EdnsOption]
lbMerge [EdnsOption]
xt [EdnsOption]
ys
Ordering
GT -> EdnsOption
y EdnsOption -> [EdnsOption] -> [EdnsOption]
forall a. a -> [a] -> [a]
: [EdnsOption] -> [EdnsOption] -> [EdnsOption]
lbMerge [EdnsOption]
xs [EdnsOption]
yt
Ordering
EQ -> [EdnsOption] -> [EdnsOption] -> [EdnsOption]
lbMerge [EdnsOption]
xs [EdnsOption]
yt
emptyOptionCtl :: OptionCtl
emptyOptionCtl :: OptionCtl
emptyOptionCtl = [EdnsOption] -> OptionCtl
OptionCtl []
applyOptionCtl :: (OptionCtl -> OptionCtl) -> [EdnsOption] -> [EdnsOption]
applyOptionCtl :: (OptionCtl -> OptionCtl) -> [EdnsOption] -> [EdnsOption]
applyOptionCtl OptionCtl -> OptionCtl
f [EdnsOption]
opts = OptionCtl -> [EdnsOption]
fromOptionCtl (OptionCtl -> [EdnsOption]) -> OptionCtl -> [EdnsOption]
forall a b. (a -> b) -> a -> b
$ OptionCtl -> OptionCtl
f ([EdnsOption] -> OptionCtl
OptionCtl [EdnsOption]
opts)