-- |
-- Module      : Net.DNSBase.Internal.Bytes
-- Description : TBD
-- Copyright   : (c) Viktor Dukhovni, 2026
-- License     : BSD-3-Clause
-- Maintainer  : ietf-dane@dukhovni.org
-- Stability   : unstable
module Net.DNSBase.Internal.Bytes
    ( Bytes16(..)
    , Bytes32(..)
    , Bytes64(..)
    , ByteString
    , ShortByteString
    ) where

import qualified Data.Base16.Types as B16
import qualified Data.Base64.Types as B64
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString.Base32.Hex as B32
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Short as SB
import qualified Data.Text as T
import Data.String (IsString(..))

import Net.DNSBase.Internal.Present
import Net.DNSBase.Internal.Util

-- | ByteStrings with a hexadecimal presentation form
newtype Bytes16 = Bytes16 { Bytes16 -> ShortByteString
getShort16 :: ShortByteString }
    deriving (Bytes16 -> Bytes16 -> Bool
(Bytes16 -> Bytes16 -> Bool)
-> (Bytes16 -> Bytes16 -> Bool) -> Eq Bytes16
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Bytes16 -> Bytes16 -> Bool
== :: Bytes16 -> Bytes16 -> Bool
$c/= :: Bytes16 -> Bytes16 -> Bool
/= :: Bytes16 -> Bytes16 -> Bool
Eq, Eq Bytes16
Eq Bytes16 =>
(Bytes16 -> Bytes16 -> Ordering)
-> (Bytes16 -> Bytes16 -> Bool)
-> (Bytes16 -> Bytes16 -> Bool)
-> (Bytes16 -> Bytes16 -> Bool)
-> (Bytes16 -> Bytes16 -> Bool)
-> (Bytes16 -> Bytes16 -> Bytes16)
-> (Bytes16 -> Bytes16 -> Bytes16)
-> Ord Bytes16
Bytes16 -> Bytes16 -> Bool
Bytes16 -> Bytes16 -> Ordering
Bytes16 -> Bytes16 -> Bytes16
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 :: Bytes16 -> Bytes16 -> Ordering
compare :: Bytes16 -> Bytes16 -> Ordering
$c< :: Bytes16 -> Bytes16 -> Bool
< :: Bytes16 -> Bytes16 -> Bool
$c<= :: Bytes16 -> Bytes16 -> Bool
<= :: Bytes16 -> Bytes16 -> Bool
$c> :: Bytes16 -> Bytes16 -> Bool
> :: Bytes16 -> Bytes16 -> Bool
$c>= :: Bytes16 -> Bytes16 -> Bool
>= :: Bytes16 -> Bytes16 -> Bool
$cmax :: Bytes16 -> Bytes16 -> Bytes16
max :: Bytes16 -> Bytes16 -> Bytes16
$cmin :: Bytes16 -> Bytes16 -> Bytes16
min :: Bytes16 -> Bytes16 -> Bytes16
Ord, NonEmpty Bytes16 -> Bytes16
Bytes16 -> Bytes16 -> Bytes16
(Bytes16 -> Bytes16 -> Bytes16)
-> (NonEmpty Bytes16 -> Bytes16)
-> (forall b. Integral b => b -> Bytes16 -> Bytes16)
-> Semigroup Bytes16
forall b. Integral b => b -> Bytes16 -> Bytes16
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: Bytes16 -> Bytes16 -> Bytes16
<> :: Bytes16 -> Bytes16 -> Bytes16
$csconcat :: NonEmpty Bytes16 -> Bytes16
sconcat :: NonEmpty Bytes16 -> Bytes16
$cstimes :: forall b. Integral b => b -> Bytes16 -> Bytes16
stimes :: forall b. Integral b => b -> Bytes16 -> Bytes16
Semigroup, Semigroup Bytes16
Bytes16
Semigroup Bytes16 =>
Bytes16
-> (Bytes16 -> Bytes16 -> Bytes16)
-> ([Bytes16] -> Bytes16)
-> Monoid Bytes16
[Bytes16] -> Bytes16
Bytes16 -> Bytes16 -> Bytes16
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
$cmempty :: Bytes16
mempty :: Bytes16
$cmappend :: Bytes16 -> Bytes16 -> Bytes16
mappend :: Bytes16 -> Bytes16 -> Bytes16
$cmconcat :: [Bytes16] -> Bytes16
mconcat :: [Bytes16] -> Bytes16
Monoid) via ShortByteString
instance Presentable Bytes16 where
    present :: Bytes16 -> Builder -> Builder
present = Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
(<>) (Builder -> Builder -> Builder)
-> (Bytes16 -> Builder) -> Bytes16 -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Builder
B.byteStringHex (StrictByteString -> Builder)
-> (Bytes16 -> StrictByteString) -> Bytes16 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes16 -> StrictByteString
fromShort16
instance Show Bytes16 where
    showsPrec :: Int -> Bytes16 -> ShowS
showsPrec Int
_ = StrictByteString -> ShowS
forall a. Show a => a -> ShowS
shows (StrictByteString -> ShowS)
-> (Bytes16 -> StrictByteString) -> Bytes16 -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base16 StrictByteString -> StrictByteString
forall a. Base16 a -> a
B16.extractBase16 (Base16 StrictByteString -> StrictByteString)
-> (Bytes16 -> Base16 StrictByteString)
-> Bytes16
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Base16 StrictByteString
B16.encodeBase16' (StrictByteString -> Base16 StrictByteString)
-> (Bytes16 -> StrictByteString)
-> Bytes16
-> Base16 StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes16 -> StrictByteString
fromShort16
instance IsString Bytes16 where
    fromString :: String -> Bytes16
fromString String
s = case StrictByteString -> Either Text StrictByteString
B16.decodeBase16Untyped (StrictByteString -> Either Text StrictByteString)
-> StrictByteString -> Either Text StrictByteString
forall a b. (a -> b) -> a -> b
$ String -> StrictByteString
BS.pack String
s of
        Right StrictByteString
bs -> StrictByteString -> Bytes16
toShort16 StrictByteString
bs
        Left Text
err -> String -> Bytes16
forall a. HasCallStack => String -> a
error (String -> Bytes16) -> String -> Bytes16
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
err


-- | ByteStrings with a base32 presentation form
newtype Bytes32 = Bytes32 { Bytes32 -> ShortByteString
getShort32 :: ShortByteString }
    deriving (Bytes32 -> Bytes32 -> Bool
(Bytes32 -> Bytes32 -> Bool)
-> (Bytes32 -> Bytes32 -> Bool) -> Eq Bytes32
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Bytes32 -> Bytes32 -> Bool
== :: Bytes32 -> Bytes32 -> Bool
$c/= :: Bytes32 -> Bytes32 -> Bool
/= :: Bytes32 -> Bytes32 -> Bool
Eq, Eq Bytes32
Eq Bytes32 =>
(Bytes32 -> Bytes32 -> Ordering)
-> (Bytes32 -> Bytes32 -> Bool)
-> (Bytes32 -> Bytes32 -> Bool)
-> (Bytes32 -> Bytes32 -> Bool)
-> (Bytes32 -> Bytes32 -> Bool)
-> (Bytes32 -> Bytes32 -> Bytes32)
-> (Bytes32 -> Bytes32 -> Bytes32)
-> Ord Bytes32
Bytes32 -> Bytes32 -> Bool
Bytes32 -> Bytes32 -> Ordering
Bytes32 -> Bytes32 -> Bytes32
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 :: Bytes32 -> Bytes32 -> Ordering
compare :: Bytes32 -> Bytes32 -> Ordering
$c< :: Bytes32 -> Bytes32 -> Bool
< :: Bytes32 -> Bytes32 -> Bool
$c<= :: Bytes32 -> Bytes32 -> Bool
<= :: Bytes32 -> Bytes32 -> Bool
$c> :: Bytes32 -> Bytes32 -> Bool
> :: Bytes32 -> Bytes32 -> Bool
$c>= :: Bytes32 -> Bytes32 -> Bool
>= :: Bytes32 -> Bytes32 -> Bool
$cmax :: Bytes32 -> Bytes32 -> Bytes32
max :: Bytes32 -> Bytes32 -> Bytes32
$cmin :: Bytes32 -> Bytes32 -> Bytes32
min :: Bytes32 -> Bytes32 -> Bytes32
Ord, NonEmpty Bytes32 -> Bytes32
Bytes32 -> Bytes32 -> Bytes32
(Bytes32 -> Bytes32 -> Bytes32)
-> (NonEmpty Bytes32 -> Bytes32)
-> (forall b. Integral b => b -> Bytes32 -> Bytes32)
-> Semigroup Bytes32
forall b. Integral b => b -> Bytes32 -> Bytes32
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: Bytes32 -> Bytes32 -> Bytes32
<> :: Bytes32 -> Bytes32 -> Bytes32
$csconcat :: NonEmpty Bytes32 -> Bytes32
sconcat :: NonEmpty Bytes32 -> Bytes32
$cstimes :: forall b. Integral b => b -> Bytes32 -> Bytes32
stimes :: forall b. Integral b => b -> Bytes32 -> Bytes32
Semigroup, Semigroup Bytes32
Bytes32
Semigroup Bytes32 =>
Bytes32
-> (Bytes32 -> Bytes32 -> Bytes32)
-> ([Bytes32] -> Bytes32)
-> Monoid Bytes32
[Bytes32] -> Bytes32
Bytes32 -> Bytes32 -> Bytes32
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
$cmempty :: Bytes32
mempty :: Bytes32
$cmappend :: Bytes32 -> Bytes32 -> Bytes32
mappend :: Bytes32 -> Bytes32 -> Bytes32
$cmconcat :: [Bytes32] -> Bytes32
mconcat :: [Bytes32] -> Bytes32
Monoid) via ShortByteString
instance Presentable Bytes32 where
    present :: Bytes32 -> Builder -> Builder
present = StrictByteString -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present (StrictByteString -> Builder -> Builder)
-> (Bytes32 -> StrictByteString) -> Bytes32 -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> StrictByteString
B32.encodeBase32Unpadded' (StrictByteString -> StrictByteString)
-> (Bytes32 -> StrictByteString) -> Bytes32 -> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes32 -> StrictByteString
fromShort32
instance Show Bytes32 where
    showsPrec :: Int -> Bytes32 -> ShowS
showsPrec Int
_ = StrictByteString -> ShowS
forall a. Show a => a -> ShowS
shows (StrictByteString -> ShowS)
-> (Bytes32 -> StrictByteString) -> Bytes32 -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> StrictByteString
B32.encodeBase32Unpadded' (StrictByteString -> StrictByteString)
-> (Bytes32 -> StrictByteString) -> Bytes32 -> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes32 -> StrictByteString
fromShort32
instance IsString Bytes32 where
    fromString :: String -> Bytes32
fromString String
s = case StrictByteString -> Either Text StrictByteString
B32.decodeBase32Unpadded (StrictByteString -> Either Text StrictByteString)
-> StrictByteString -> Either Text StrictByteString
forall a b. (a -> b) -> a -> b
$ String -> StrictByteString
BS.pack String
s of
        Right StrictByteString
bs -> StrictByteString -> Bytes32
toShort32 StrictByteString
bs
        Left Text
err -> String -> Bytes32
forall a. HasCallStack => String -> a
error (String -> Bytes32) -> String -> Bytes32
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
err


-- | ByteStrings with a base64 presentation form
newtype Bytes64 = Bytes64 { Bytes64 -> ShortByteString
getShort64 :: ShortByteString }
    deriving (Bytes64 -> Bytes64 -> Bool
(Bytes64 -> Bytes64 -> Bool)
-> (Bytes64 -> Bytes64 -> Bool) -> Eq Bytes64
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Bytes64 -> Bytes64 -> Bool
== :: Bytes64 -> Bytes64 -> Bool
$c/= :: Bytes64 -> Bytes64 -> Bool
/= :: Bytes64 -> Bytes64 -> Bool
Eq, Eq Bytes64
Eq Bytes64 =>
(Bytes64 -> Bytes64 -> Ordering)
-> (Bytes64 -> Bytes64 -> Bool)
-> (Bytes64 -> Bytes64 -> Bool)
-> (Bytes64 -> Bytes64 -> Bool)
-> (Bytes64 -> Bytes64 -> Bool)
-> (Bytes64 -> Bytes64 -> Bytes64)
-> (Bytes64 -> Bytes64 -> Bytes64)
-> Ord Bytes64
Bytes64 -> Bytes64 -> Bool
Bytes64 -> Bytes64 -> Ordering
Bytes64 -> Bytes64 -> Bytes64
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 :: Bytes64 -> Bytes64 -> Ordering
compare :: Bytes64 -> Bytes64 -> Ordering
$c< :: Bytes64 -> Bytes64 -> Bool
< :: Bytes64 -> Bytes64 -> Bool
$c<= :: Bytes64 -> Bytes64 -> Bool
<= :: Bytes64 -> Bytes64 -> Bool
$c> :: Bytes64 -> Bytes64 -> Bool
> :: Bytes64 -> Bytes64 -> Bool
$c>= :: Bytes64 -> Bytes64 -> Bool
>= :: Bytes64 -> Bytes64 -> Bool
$cmax :: Bytes64 -> Bytes64 -> Bytes64
max :: Bytes64 -> Bytes64 -> Bytes64
$cmin :: Bytes64 -> Bytes64 -> Bytes64
min :: Bytes64 -> Bytes64 -> Bytes64
Ord, NonEmpty Bytes64 -> Bytes64
Bytes64 -> Bytes64 -> Bytes64
(Bytes64 -> Bytes64 -> Bytes64)
-> (NonEmpty Bytes64 -> Bytes64)
-> (forall b. Integral b => b -> Bytes64 -> Bytes64)
-> Semigroup Bytes64
forall b. Integral b => b -> Bytes64 -> Bytes64
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
$c<> :: Bytes64 -> Bytes64 -> Bytes64
<> :: Bytes64 -> Bytes64 -> Bytes64
$csconcat :: NonEmpty Bytes64 -> Bytes64
sconcat :: NonEmpty Bytes64 -> Bytes64
$cstimes :: forall b. Integral b => b -> Bytes64 -> Bytes64
stimes :: forall b. Integral b => b -> Bytes64 -> Bytes64
Semigroup, Semigroup Bytes64
Bytes64
Semigroup Bytes64 =>
Bytes64
-> (Bytes64 -> Bytes64 -> Bytes64)
-> ([Bytes64] -> Bytes64)
-> Monoid Bytes64
[Bytes64] -> Bytes64
Bytes64 -> Bytes64 -> Bytes64
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
$cmempty :: Bytes64
mempty :: Bytes64
$cmappend :: Bytes64 -> Bytes64 -> Bytes64
mappend :: Bytes64 -> Bytes64 -> Bytes64
$cmconcat :: [Bytes64] -> Bytes64
mconcat :: [Bytes64] -> Bytes64
Monoid) via ShortByteString
instance Presentable Bytes64 where
    present :: Bytes64 -> Builder -> Builder
present = StrictByteString -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present (StrictByteString -> Builder -> Builder)
-> (Bytes64 -> StrictByteString) -> Bytes64 -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 'StdPadded StrictByteString -> StrictByteString
forall (k :: Alphabet) a. Base64 k a -> a
B64.extractBase64 (Base64 'StdPadded StrictByteString -> StrictByteString)
-> (Bytes64 -> Base64 'StdPadded StrictByteString)
-> Bytes64
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Base64 'StdPadded StrictByteString
B64.encodeBase64' (StrictByteString -> Base64 'StdPadded StrictByteString)
-> (Bytes64 -> StrictByteString)
-> Bytes64
-> Base64 'StdPadded StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes64 -> StrictByteString
fromShort64
instance Show Bytes64 where
    showsPrec :: Int -> Bytes64 -> ShowS
showsPrec Int
_ = StrictByteString -> ShowS
forall a. Show a => a -> ShowS
shows (StrictByteString -> ShowS)
-> (Bytes64 -> StrictByteString) -> Bytes64 -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64 'StdPadded StrictByteString -> StrictByteString
forall (k :: Alphabet) a. Base64 k a -> a
B64.extractBase64 (Base64 'StdPadded StrictByteString -> StrictByteString)
-> (Bytes64 -> Base64 'StdPadded StrictByteString)
-> Bytes64
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> Base64 'StdPadded StrictByteString
B64.encodeBase64' (StrictByteString -> Base64 'StdPadded StrictByteString)
-> (Bytes64 -> StrictByteString)
-> Bytes64
-> Base64 'StdPadded StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes64 -> StrictByteString
fromShort64
instance IsString Bytes64 where
    fromString :: String -> Bytes64
fromString String
s = case StrictByteString -> Either Text StrictByteString
B64.decodeBase64Untyped (StrictByteString -> Either Text StrictByteString)
-> StrictByteString -> Either Text StrictByteString
forall a b. (a -> b) -> a -> b
$ String -> StrictByteString
BS.pack String
s of
        Right StrictByteString
bs -> StrictByteString -> Bytes64
toShort64 StrictByteString
bs
        Left Text
err -> String -> Bytes64
forall a. HasCallStack => String -> a
error (String -> Bytes64) -> String -> Bytes64
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
err

fromShort16 :: Bytes16 -> ByteString
fromShort16 :: Bytes16 -> StrictByteString
fromShort16 = ShortByteString -> StrictByteString
SB.fromShort (ShortByteString -> StrictByteString)
-> (Bytes16 -> ShortByteString) -> Bytes16 -> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes16 -> ShortByteString
forall a b. Coercible a b => a -> b
coerce

fromShort32 :: Bytes32 -> ByteString
fromShort32 :: Bytes32 -> StrictByteString
fromShort32 = ShortByteString -> StrictByteString
SB.fromShort (ShortByteString -> StrictByteString)
-> (Bytes32 -> ShortByteString) -> Bytes32 -> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes32 -> ShortByteString
forall a b. Coercible a b => a -> b
coerce

fromShort64 :: Bytes64 -> ByteString
fromShort64 :: Bytes64 -> StrictByteString
fromShort64 = ShortByteString -> StrictByteString
SB.fromShort (ShortByteString -> StrictByteString)
-> (Bytes64 -> ShortByteString) -> Bytes64 -> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bytes64 -> ShortByteString
forall a b. Coercible a b => a -> b
coerce

toShort16 :: ByteString -> Bytes16
toShort16 :: StrictByteString -> Bytes16
toShort16 = ShortByteString -> Bytes16
forall a b. Coercible a b => a -> b
coerce (ShortByteString -> Bytes16)
-> (StrictByteString -> ShortByteString)
-> StrictByteString
-> Bytes16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> ShortByteString
SB.toShort

toShort32 :: ByteString -> Bytes32
toShort32 :: StrictByteString -> Bytes32
toShort32 = ShortByteString -> Bytes32
forall a b. Coercible a b => a -> b
coerce (ShortByteString -> Bytes32)
-> (StrictByteString -> ShortByteString)
-> StrictByteString
-> Bytes32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> ShortByteString
SB.toShort

toShort64 :: ByteString -> Bytes64
toShort64 :: StrictByteString -> Bytes64
toShort64 = ShortByteString -> Bytes64
forall a b. Coercible a b => a -> b
coerce (ShortByteString -> Bytes64)
-> (StrictByteString -> ShortByteString)
-> StrictByteString
-> Bytes64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StrictByteString -> ShortByteString
SB.toShort