{-# LANGUAGE CPP                #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric      #-}
-- | Strict 'ByteString' base64 encoding with URL and filename safe alphabet.
--
-- See <https://tools.ietf.org/html/rfc4648>.
module Data.ByteString.Base64.URL.Type (
    ByteString64,
    makeByteString64,
    getByteString64,
    mkBS64,
    getBS64,
    getEncodedByteString64,
  ) where

import Prelude ()
import Prelude.Compat

import Control.DeepSeq    (NFData (..))
import Data.Aeson
       (FromJSON (..), FromJSONKey (..), ToJSON (..), ToJSONKey (..), withText)
import Data.Aeson.Types   (FromJSONKeyFunction (..), toJSONKeyText)
import Data.Binary        (Binary (..))
import Data.ByteString    (ByteString, pack, unpack)
import Data.Data          (Data, Typeable)
import Data.Hashable      (Hashable)
import Data.Semigroup     (Semigroup (..))
import Data.String        (IsString (..))
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
import GHC.Generics       (Generic)
import Test.QuickCheck
       (Arbitrary (..), CoArbitrary (..), Function (..), functionMap,
       shrinkMap)

import qualified Data.ByteString.Base64.URL as Base64
import qualified Data.Text                  as T

#ifdef MIN_VERSION_cereal
import Data.Serialize (Serialize)
#endif

#ifdef MIN_VERSION_serialise
import Codec.Serialise (Serialise (..))
#endif

#ifdef MIN_VERSION_http_api_data
import Web.HttpApiData (FromHttpApiData (..), ToHttpApiData (..))
#endif

-- | Aeson serialisable bytestring. Uses base64 encoding.
--
-- The inner 'ByteString' is in raw format.
--
-- >>> let bs64 = makeByteString64 "foobar"
-- >>> bs64
-- mkBS64 "foobar"
--
-- 'Binary' instance doesn't use base64 encoding:
--
-- >>> Binary.encode bs64
-- "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ACKfoobar"
--
-- 'Aeson' instance does:
--
-- >>> Aeson.encode bs64
-- "\"Zm9vYmFy\""
--
-- This module uses standard alphabet
--
-- >>> Aeson.encode (makeByteString64 "aa\191")
-- "\"YWG_\""
--
newtype ByteString64 = BS64 ByteString
    deriving (ByteString64 -> ByteString64 -> Bool
(ByteString64 -> ByteString64 -> Bool)
-> (ByteString64 -> ByteString64 -> Bool) -> Eq ByteString64
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ByteString64 -> ByteString64 -> Bool
$c/= :: ByteString64 -> ByteString64 -> Bool
== :: ByteString64 -> ByteString64 -> Bool
$c== :: ByteString64 -> ByteString64 -> Bool
Eq, Eq ByteString64
Eq ByteString64
-> (ByteString64 -> ByteString64 -> Ordering)
-> (ByteString64 -> ByteString64 -> Bool)
-> (ByteString64 -> ByteString64 -> Bool)
-> (ByteString64 -> ByteString64 -> Bool)
-> (ByteString64 -> ByteString64 -> Bool)
-> (ByteString64 -> ByteString64 -> ByteString64)
-> (ByteString64 -> ByteString64 -> ByteString64)
-> Ord ByteString64
ByteString64 -> ByteString64 -> Bool
ByteString64 -> ByteString64 -> Ordering
ByteString64 -> ByteString64 -> ByteString64
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
min :: ByteString64 -> ByteString64 -> ByteString64
$cmin :: ByteString64 -> ByteString64 -> ByteString64
max :: ByteString64 -> ByteString64 -> ByteString64
$cmax :: ByteString64 -> ByteString64 -> ByteString64
>= :: ByteString64 -> ByteString64 -> Bool
$c>= :: ByteString64 -> ByteString64 -> Bool
> :: ByteString64 -> ByteString64 -> Bool
$c> :: ByteString64 -> ByteString64 -> Bool
<= :: ByteString64 -> ByteString64 -> Bool
$c<= :: ByteString64 -> ByteString64 -> Bool
< :: ByteString64 -> ByteString64 -> Bool
$c< :: ByteString64 -> ByteString64 -> Bool
compare :: ByteString64 -> ByteString64 -> Ordering
$ccompare :: ByteString64 -> ByteString64 -> Ordering
$cp1Ord :: Eq ByteString64
Ord, Typeable ByteString64
DataType
Constr
Typeable ByteString64
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> ByteString64 -> c ByteString64)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c ByteString64)
-> (ByteString64 -> Constr)
-> (ByteString64 -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c ByteString64))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c ByteString64))
-> ((forall b. Data b => b -> b) -> ByteString64 -> ByteString64)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> ByteString64 -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> ByteString64 -> r)
-> (forall u. (forall d. Data d => d -> u) -> ByteString64 -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> ByteString64 -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64)
-> Data ByteString64
ByteString64 -> DataType
ByteString64 -> Constr
(forall b. Data b => b -> b) -> ByteString64 -> ByteString64
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteString64 -> c ByteString64
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteString64
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> ByteString64 -> u
forall u. (forall d. Data d => d -> u) -> ByteString64 -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteString64
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteString64 -> c ByteString64
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ByteString64)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c ByteString64)
$cBS64 :: Constr
$tByteString64 :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
gmapMp :: (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
gmapM :: (forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ByteString64 -> m ByteString64
gmapQi :: Int -> (forall d. Data d => d -> u) -> ByteString64 -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ByteString64 -> u
gmapQ :: (forall d. Data d => d -> u) -> ByteString64 -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> ByteString64 -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteString64 -> r
gmapT :: (forall b. Data b => b -> b) -> ByteString64 -> ByteString64
$cgmapT :: (forall b. Data b => b -> b) -> ByteString64 -> ByteString64
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c ByteString64)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c ByteString64)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c ByteString64)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ByteString64)
dataTypeOf :: ByteString64 -> DataType
$cdataTypeOf :: ByteString64 -> DataType
toConstr :: ByteString64 -> Constr
$ctoConstr :: ByteString64 -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteString64
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteString64
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteString64 -> c ByteString64
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteString64 -> c ByteString64
$cp1Data :: Typeable ByteString64
Data, Typeable, (forall x. ByteString64 -> Rep ByteString64 x)
-> (forall x. Rep ByteString64 x -> ByteString64)
-> Generic ByteString64
forall x. Rep ByteString64 x -> ByteString64
forall x. ByteString64 -> Rep ByteString64 x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ByteString64 x -> ByteString64
$cfrom :: forall x. ByteString64 -> Rep ByteString64 x
Generic)

instance Show ByteString64 where
    showsPrec :: Int -> ByteString64 -> ShowS
showsPrec Int
d (BS64 ByteString
bs) = Bool -> ShowS -> ShowS
showParen (Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String -> ShowS
showString String
"mkBS64 " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 ByteString
bs

-- | Wrap 'ByteString' into 'ByteString64'. Essentially 'coerce'.
makeByteString64 :: ByteString -> ByteString64
makeByteString64 :: ByteString -> ByteString64
makeByteString64 = ByteString -> ByteString64
BS64

-- | Shorter variant of 'makeByteString64'
mkBS64 :: ByteString -> ByteString64
mkBS64 :: ByteString -> ByteString64
mkBS64 = ByteString -> ByteString64
makeByteString64

-- | Unwrap 'ByteString' from 'ByteString64'. Essentially 'coerce'.
getByteString64 :: ByteString64 -> ByteString
getByteString64 :: ByteString64 -> ByteString
getByteString64 = \(BS64 ByteString
bs) -> ByteString
bs

--  | Shorter variant of 'getByteString64'
getBS64 :: ByteString64 -> ByteString
getBS64 :: ByteString64 -> ByteString
getBS64 = \(BS64 ByteString
bs) -> ByteString
bs

-- | Get base64 encode bytestring
--
-- >>> getEncodedByteString64 "foobar"
-- "Zm9vYmFy"
--
-- >>> getEncodedByteString64 "aa\191"
-- "YWG_"
--
getEncodedByteString64 :: ByteString64 -> ByteString
getEncodedByteString64 :: ByteString64 -> ByteString
getEncodedByteString64 = ByteString -> ByteString
Base64.encode (ByteString -> ByteString)
-> (ByteString64 -> ByteString) -> ByteString64 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64

-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------

instance IsString ByteString64 where
   fromString :: String -> ByteString64
fromString = ByteString -> ByteString64
BS64 (ByteString -> ByteString64)
-> (String -> ByteString) -> String -> ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
forall a. IsString a => String -> a
fromString

instance Semigroup ByteString64 where
    BS64 ByteString
a <> :: ByteString64 -> ByteString64 -> ByteString64
<> BS64 ByteString
b = ByteString -> ByteString64
BS64 (ByteString
a ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
b)

instance Monoid ByteString64 where
    mempty :: ByteString64
mempty = ByteString -> ByteString64
BS64 ByteString
forall a. Monoid a => a
mempty
    mappend :: ByteString64 -> ByteString64 -> ByteString64
mappend = ByteString64 -> ByteString64 -> ByteString64
forall a. Semigroup a => a -> a -> a
(<>)

instance NFData ByteString64 where rnf :: ByteString64 -> ()
rnf ByteString64
x = ByteString64
x ByteString64 -> () -> ()
`seq` ()
instance Hashable ByteString64

-------------------------------------------------------------------------------
-- aeson
-------------------------------------------------------------------------------

instance ToJSON ByteString64 where
    toJSON :: ByteString64 -> Value
toJSON = Text -> Value
forall a. ToJSON a => a -> Value
toJSON (Text -> Value) -> (ByteString64 -> Text) -> ByteString64 -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeLatin1 (ByteString -> Text)
-> (ByteString64 -> ByteString) -> ByteString64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getEncodedByteString64
    toEncoding :: ByteString64 -> Encoding
toEncoding = Text -> Encoding
forall a. ToJSON a => a -> Encoding
toEncoding (Text -> Encoding)
-> (ByteString64 -> Text) -> ByteString64 -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeLatin1 (ByteString -> Text)
-> (ByteString64 -> ByteString) -> ByteString64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getEncodedByteString64

instance FromJSON ByteString64 where
    parseJSON :: Value -> Parser ByteString64
parseJSON = String
-> (Text -> Parser ByteString64) -> Value -> Parser ByteString64
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"ByteString" ((Text -> Parser ByteString64) -> Value -> Parser ByteString64)
-> (Text -> Parser ByteString64) -> Value -> Parser ByteString64
forall a b. (a -> b) -> a -> b
$
        (String -> Parser ByteString64)
-> (ByteString -> Parser ByteString64)
-> Either String ByteString
-> Parser ByteString64
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser ByteString64
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (ByteString64 -> Parser ByteString64
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString64 -> Parser ByteString64)
-> (ByteString -> ByteString64)
-> ByteString
-> Parser ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString64
BS64) (Either String ByteString -> Parser ByteString64)
-> (Text -> Either String ByteString)
-> Text
-> Parser ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String ByteString
Base64.decode (ByteString -> Either String ByteString)
-> (Text -> ByteString) -> Text -> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8

instance ToJSONKey ByteString64 where
    toJSONKey :: ToJSONKeyFunction ByteString64
toJSONKey = (ByteString64 -> Text) -> ToJSONKeyFunction ByteString64
forall a. (a -> Text) -> ToJSONKeyFunction a
toJSONKeyText (ByteString -> Text
decodeLatin1 (ByteString -> Text)
-> (ByteString64 -> ByteString) -> ByteString64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getEncodedByteString64)

instance FromJSONKey ByteString64 where
    fromJSONKey :: FromJSONKeyFunction ByteString64
fromJSONKey = (Text -> Parser ByteString64) -> FromJSONKeyFunction ByteString64
forall a. (Text -> Parser a) -> FromJSONKeyFunction a
FromJSONKeyTextParser ((Text -> Parser ByteString64) -> FromJSONKeyFunction ByteString64)
-> (Text -> Parser ByteString64)
-> FromJSONKeyFunction ByteString64
forall a b. (a -> b) -> a -> b
$
        (String -> Parser ByteString64)
-> (ByteString -> Parser ByteString64)
-> Either String ByteString
-> Parser ByteString64
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> Parser ByteString64
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (ByteString64 -> Parser ByteString64
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString64 -> Parser ByteString64)
-> (ByteString -> ByteString64)
-> ByteString
-> Parser ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString64
BS64) (Either String ByteString -> Parser ByteString64)
-> (Text -> Either String ByteString)
-> Text
-> Parser ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String ByteString
Base64.decode (ByteString -> Either String ByteString)
-> (Text -> ByteString) -> Text -> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8

-------------------------------------------------------------------------------
-- cereal
-------------------------------------------------------------------------------

#ifdef MIN_VERSION_cereal
-- | 'ByteString64' is serialised as 'ByteString'
--
-- >>> Cereal.encode (mkBS64 "foobar")
-- "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ACKfoobar"
instance Serialize ByteString64
#endif

-------------------------------------------------------------------------------
-- binary
-------------------------------------------------------------------------------

-- | 'ByteString64' is serialised as 'ByteString'
--
-- >>> Binary.encode (mkBS64 "foobar")
-- "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ACKfoobar"
instance Binary ByteString64 where
    put :: ByteString64 -> Put
put = ByteString -> Put
forall t. Binary t => t -> Put
put (ByteString -> Put)
-> (ByteString64 -> ByteString) -> ByteString64 -> Put
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64
    get :: Get ByteString64
get = (ByteString -> ByteString64) -> Get ByteString -> Get ByteString64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString64
makeByteString64 Get ByteString
forall t. Binary t => Get t
get

-------------------------------------------------------------------------------
-- serialise
-------------------------------------------------------------------------------

#ifdef MIN_VERSION_serialise
-- | >>> Serialise.serialise (mkBS64 "xyzzy")
-- "Exyzzy"
instance Serialise ByteString64 where
    encode :: ByteString64 -> Encoding
encode = ByteString -> Encoding
forall a. Serialise a => a -> Encoding
encode (ByteString -> Encoding)
-> (ByteString64 -> ByteString) -> ByteString64 -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64
    decode :: Decoder s ByteString64
decode = (ByteString -> ByteString64)
-> Decoder s ByteString -> Decoder s ByteString64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString64
makeByteString64 Decoder s ByteString
forall a s. Serialise a => Decoder s a
decode
#endif

-------------------------------------------------------------------------------
-- http-api-data
-------------------------------------------------------------------------------

#ifdef MIN_VERSION_http_api_data
-- | >>> HTTP.toUrlPiece (mkBS64 $ pack [164..192])
-- "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2-v8A="
instance ToHttpApiData ByteString64 where
    toUrlPiece :: ByteString64 -> Text
toUrlPiece = ByteString -> Text
decodeLatin1 (ByteString -> Text)
-> (ByteString64 -> ByteString) -> ByteString64 -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getEncodedByteString64
    toHeader :: ByteString64 -> ByteString
toHeader = ByteString64 -> ByteString
getEncodedByteString64

instance FromHttpApiData ByteString64 where
    parseUrlPiece :: Text -> Either Text ByteString64
parseUrlPiece = (String -> Either Text ByteString64)
-> (ByteString -> Either Text ByteString64)
-> Either String ByteString
-> Either Text ByteString64
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> Either Text ByteString64
forall a b. a -> Either a b
Left (Text -> Either Text ByteString64)
-> (String -> Text) -> String -> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
.String -> Text
T.pack) (ByteString64 -> Either Text ByteString64
forall a b. b -> Either a b
Right (ByteString64 -> Either Text ByteString64)
-> (ByteString -> ByteString64)
-> ByteString
-> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString64
mkBS64) (Either String ByteString -> Either Text ByteString64)
-> (Text -> Either String ByteString)
-> Text
-> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String ByteString
Base64.decode (ByteString -> Either String ByteString)
-> (Text -> ByteString) -> Text -> Either String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8
    parseHeader :: ByteString -> Either Text ByteString64
parseHeader = (String -> Either Text ByteString64)
-> (ByteString -> Either Text ByteString64)
-> Either String ByteString
-> Either Text ByteString64
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> Either Text ByteString64
forall a b. a -> Either a b
Left (Text -> Either Text ByteString64)
-> (String -> Text) -> String -> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) (ByteString64 -> Either Text ByteString64
forall a b. b -> Either a b
Right (ByteString64 -> Either Text ByteString64)
-> (ByteString -> ByteString64)
-> ByteString
-> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString64
mkBS64) (Either String ByteString -> Either Text ByteString64)
-> (ByteString -> Either String ByteString)
-> ByteString
-> Either Text ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String ByteString
Base64.decode
#endif

-------------------------------------------------------------------------------
-- QuickCheck
-------------------------------------------------------------------------------

instance Arbitrary ByteString64 where
    arbitrary :: Gen ByteString64
arbitrary = ByteString -> ByteString64
BS64 (ByteString -> ByteString64)
-> ([Word8] -> ByteString) -> [Word8] -> ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
pack ([Word8] -> ByteString64) -> Gen [Word8] -> Gen ByteString64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [Word8]
forall a. Arbitrary a => Gen a
arbitrary
    shrink :: ByteString64 -> [ByteString64]
shrink = ([Word8] -> ByteString64)
-> (ByteString64 -> [Word8]) -> ByteString64 -> [ByteString64]
forall a b. Arbitrary a => (a -> b) -> (b -> a) -> b -> [b]
shrinkMap (ByteString -> ByteString64
BS64 (ByteString -> ByteString64)
-> ([Word8] -> ByteString) -> [Word8] -> ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
pack) (ByteString -> [Word8]
unpack (ByteString -> [Word8])
-> (ByteString64 -> ByteString) -> ByteString64 -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64)

instance CoArbitrary ByteString64 where
    coarbitrary :: ByteString64 -> Gen b -> Gen b
coarbitrary = [Word8] -> Gen b -> Gen b
forall a b. CoArbitrary a => a -> Gen b -> Gen b
coarbitrary ([Word8] -> Gen b -> Gen b)
-> (ByteString64 -> [Word8]) -> ByteString64 -> Gen b -> Gen b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Word8]
unpack (ByteString -> [Word8])
-> (ByteString64 -> ByteString) -> ByteString64 -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64

instance Function ByteString64 where
    function :: (ByteString64 -> b) -> ByteString64 :-> b
function = (ByteString64 -> [Word8])
-> ([Word8] -> ByteString64)
-> (ByteString64 -> b)
-> ByteString64 :-> b
forall b a c.
Function b =>
(a -> b) -> (b -> a) -> (a -> c) -> a :-> c
functionMap (ByteString -> [Word8]
unpack (ByteString -> [Word8])
-> (ByteString64 -> ByteString) -> ByteString64 -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString64 -> ByteString
getBS64) (ByteString -> ByteString64
BS64 (ByteString -> ByteString64)
-> ([Word8] -> ByteString) -> [Word8] -> ByteString64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
pack)

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import qualified Codec.Serialise as Serialise
-- >>> import qualified Data.Serialize as Cereal
-- >>> import qualified Data.Binary as Binary
-- >>> import qualified Data.Aeson as Aeson
-- >>> import qualified Web.HttpApiData as HTTP