{-# language DataKinds #-}
{-# language RankNTypes #-}
{-# language TypeFamilies #-}
-- |
-- Module       : Data.ByteString.Base64.Types.Internal
-- Copyright    : (c) 2019-2023 Emily Pillmore
-- License      : BSD-style
--
-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>,
--                sofia-m-a <https://github.com/sofia-m-a>
-- Stability    : stable
-- Portability  : non-portable
--
-- This module contains the 'Base64' newtype, 'Alphabet'
-- datatype, and associated instances for 'Base64'.
--
module Data.Base64.Types.Internal
( Alphabet(..)
, Base64(..)
) where


import Control.DeepSeq (NFData, rnf)

-- | The different kinds of supported Base64 encodings
data Alphabet
  = StdPadded
    -- ^ Standard base64 according to [RFC 4648 §4](https://datatracker.ietf.org/doc/html/rfc4648#section-4)
    -- Padding is always inserted when encoding, and required when decoding
  | UrlPadded
    -- ^ Standard base64 according to [RFC 4648 §4](https://datatracker.ietf.org/doc/html/rfc4648#section-4)
    -- Padding is never inserted when encoding, and optional when decoding per
    -- [RFC 7049](https://datatracker.ietf.org/doc/html/rfc7049#section-2.4.4.2).
  | UrlUnpadded
    -- ^ URL-safe base64 according to [RFC 4648 §5](https://datatracker.ietf.org/doc/html/rfc4648#section-5) aka base64url
    -- Padding is never inserted when encoding, and optional when decoding
  | NonStandard
    -- ^ Any non-standard, non RFC 4648-compliant base64 encoding.
    -- Can only be decoded using lenient decoders.

-- | Wraps a value, asserting that it is or is intended to be
-- in a particular kind of Base64 encoding use 'extractBase64'
-- to extract the value, and 'assertBase64' to tag a value
-- as base64-encoded
--
newtype Base64 (k :: Alphabet) a = Base64 a

instance forall k. Functor (Base64 k) where
  fmap :: forall a b. (a -> b) -> Base64 k a -> Base64 k b
fmap a -> b
f (Base64 a
a) = b -> Base64 k b
forall (k :: Alphabet) a. a -> Base64 k a
Base64 (a -> b
f a
a)

instance forall k a. (Eq a) => Eq (Base64 k a) where
  Base64 a
a == :: Base64 k a -> Base64 k a -> Bool
== Base64 a
b = a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
b

instance forall k. Applicative (Base64 k) where
  pure :: forall a. a -> Base64 k a
pure = a -> Base64 k a
forall (k :: Alphabet) a. a -> Base64 k a
Base64
  Base64 a -> b
f <*> :: forall a b. Base64 k (a -> b) -> Base64 k a -> Base64 k b
<*> Base64 a
a = b -> Base64 k b
forall (k :: Alphabet) a. a -> Base64 k a
Base64 (a -> b
f a
a)

instance forall k. Monad (Base64 k) where
  return :: forall a. a -> Base64 k a
return = a -> Base64 k a
forall a. a -> Base64 k a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  Base64 a
a >>= :: forall a b. Base64 k a -> (a -> Base64 k b) -> Base64 k b
>>= a -> Base64 k b
k = a -> Base64 k b
k a
a

instance forall k a. (Show a) => Show (Base64 k a) where
  show :: Base64 k a -> String
show (Base64 a
a) = a -> String
forall a. Show a => a -> String
show a
a

instance forall k a. NFData a => NFData (Base64 k a) where
  rnf :: Base64 k a -> ()
rnf (Base64 a
a) = a -> ()
forall a. NFData a => a -> ()
rnf a
a