{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
module Data.ByteString.BaseN
( Base(..)
, AtBase
, encodedBytes
, encodedBuilder
, Base2
, Base16
, Base58
, Base64
, BaseIdentity
, Base16upper
, Base32hex
, Base32hexupper
, Base32hexpad
, Base32hexpadupper
, Base32
, Base32z
, Base32upper
, Base32pad
, Base32padupper
, Base58flickr
, Base58btc
, Base64pad
, Base64url
, Base64urlpad
, AtBaseCompact
, compact
, expand
, Base16Of
, Base58Of
, Base64Of
, tagWith
, unTagged
, DeserialiseError(..)
, deserialiseAtBase
, encodeBase16
, encodeBase58btc
, encodeBase64
, encodeAtBase
, DecodeBase
, decodeBase16
, decodeBase16Either
, decodeBase58btc
, decodeBase64
, decodeBase64Either
, decodeBase64Lenient
, decodeAtBase
, decodeAtBaseEither
, decode
, ValidBase
, validBase16
, validBase16Either
, validBase58btc
, validBase58btcEither
, validBase64
, validBase64Either
, validAtBase
, validAtBaseEither
, validAndDecoded
, validAndDecodedEither
, encodedTextAtBase
, encodedText
, encodedTextBuilder
, format
, formatAtBase
) where
import Prelude
import qualified Codec.Binary.Base32 as Base32
import qualified Codec.Binary.Base32Hex as Base32Hex
import Codec.Serialise
( DeserialiseFailure
, Serialise
, deserialiseOrFail
)
import Control.DeepSeq (NFData)
import Data.Aeson
( FromJSON(..)
, FromJSONKey
, ToJSON(..)
, ToJSONKey
, withText
)
import qualified Data.Aeson.Encoding as JSON
import Data.Bifunctor (bimap, first, second)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Base32.Z as Base32z
import qualified Data.ByteString.Base58 as Base58
import qualified Data.ByteString.Base64 as Base64
import qualified Data.ByteString.Base64.URL as Base64Url
import Data.ByteString.Builder (Builder)
import qualified Data.ByteString.Builder as Builder
import Data.ByteString.Char8 (unpack)
import qualified Data.ByteString.Char8 as C8
import Data.ByteString.Lazy (fromStrict)
import Data.ByteString.Short (ShortByteString)
import qualified Data.ByteString.Short as Short
import Data.Char (toLower, toUpper)
import Data.Hashable (Hashable)
import Data.Proxy (Proxy(..))
import Data.String (IsString(..))
import Data.Tagged (Tagged, tagWith, unTagged)
import Data.Text (Text)
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
import qualified Data.Text.Lazy.Builder as T
import qualified Formatting
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import Text.Show (Show(..), showParen, showString)
data Base (a :: Symbol) where
BaseIdentity :: Base "id"
Base2 :: Base "2"
Base16 :: Base "16"
Base64 :: Base "64"
Base16upper :: Base "16u"
Base32hex :: Base "32x"
Base32hexupper :: Base "32xu"
Base32hexpad :: Base "32xp"
Base32hexpadupper :: Base "32xpu"
Base32 :: Base "32"
Base32z :: Base "32z"
Base32upper :: Base "32u"
Base32pad :: Base "32p"
Base32padupper :: Base "32pu"
Base58flickr :: Base "58flickr"
Base58btc :: Base "58btc"
Base64pad :: Base "64p"
Base64url :: Base "64url"
Base64urlpad :: Base "64urlp"
newtype AtBase (b :: Symbol) = BaseN { fromAtBase :: ByteString }
deriving (Eq, Ord, NFData, Hashable)
encodedBytes :: AtBase b -> ByteString
encodedBytes (BaseN bs) = bs
encodedBuilder :: AtBase b -> Builder
encodedBuilder = Builder.byteString . encodedBytes
instance KnownSymbol b => Show (AtBase b) where
showsPrec p (BaseN bs) = showParen (p >= 11)
( showString ("Base" <> show (symbolVal (Proxy @b)) <> " ")
. showsPrec 11 bs
)
instance ValidBase b => IsString (AtBase b) where
fromString = either error id . validAtBaseEither (Proxy @b) . C8.pack
instance ToJSON (AtBase b) where
toJSON = toJSON . encodedText
toEncoding = JSON.text . encodedText
instance (ValidBase b, KnownSymbol b) => FromJSON (AtBase b) where
parseJSON =
withText ("AtBase " <> show (symbolVal (Proxy @b))) $
either fail pure . validAtBaseEither (Proxy @b) . encodeUtf8
instance ToJSONKey (AtBase b)
instance (ValidBase b, KnownSymbol b) => FromJSONKey (AtBase b)
type Base2 = AtBase "2"
type Base16 = AtBase "16"
type Base58 = AtBase "58"
type Base64 = AtBase "64"
type BaseIdentity = AtBase "id"
type Base16upper = AtBase "16u"
type Base32hex = AtBase "16x"
type Base32hexupper = AtBase "16xu"
type Base32hexpad = AtBase "16xp"
type Base32hexpadupper = AtBase "16xup"
type Base32 = AtBase "32"
type Base32z = AtBase "32z"
type Base32upper = AtBase "32u"
type Base32pad = AtBase "32p"
type Base32padupper = AtBase "32pu"
type Base58flickr = AtBase "58flickr"
type Base58btc = AtBase "58btc"
type Base64pad = AtBase "64p"
type Base64url = AtBase "64url"
type Base64urlpad = AtBase "16urlp"
newtype AtBaseCompact (b :: Symbol) = BaseNShort
{ fromAtBaseCompact :: ShortByteString
} deriving (Eq, Ord, Hashable, NFData)
instance KnownSymbol b => Show (AtBaseCompact b) where
showsPrec p (BaseNShort bs) = showParen (p >= 11)
( showString ("Base" <> show (symbolVal (Proxy @b)) <> "Compact ")
. showsPrec 11 bs
)
compact :: AtBase b -> AtBaseCompact b
compact = BaseNShort . Short.toShort . fromAtBase
expand :: AtBaseCompact b -> AtBase b
expand = BaseN . Short.fromShort . fromAtBaseCompact
type Base16Of a = Tagged a (AtBase "16")
type Base58Of a = Tagged a (AtBase "58")
type Base64Of a = Tagged a (AtBase "64")
data DeserialiseError =
DecodeBaseError String
| DeserialiseError DeserialiseFailure
deriving Show
deserialiseAtBase
:: ( Serialise a
, DecodeBase b
)
=> proxy b
-> ByteString
-> Either DeserialiseError a
deserialiseAtBase base bs = do
bs' <- bimap DecodeBaseError fromStrict $ decodeAtBaseEither base bs
first DeserialiseError $ deserialiseOrFail bs'
encodeBase16 :: ByteString -> AtBase "16"
encodeBase16 = BaseN . Base16.encode
{-# INLINE encodeBase16 #-}
encodeBase64 :: ByteString -> AtBase "64"
encodeBase64 = BaseN . Base64.encode
{-# INLINE encodeBase64 #-}
encodeBase16upper :: ByteString -> AtBase "16u"
encodeBase16upper = BaseN . C8.map toUpper . Base16.encode
{-# INLINE encodeBase16upper #-}
decodeBase16upper :: ByteString -> Either String ByteString
decodeBase16upper = decodeBase16Either
{-# INLINE decodeBase16upper #-}
encodeBase32hex :: ByteString -> AtBase "32x"
encodeBase32hex = BaseN . C8.map toLower . dropPadding . Base32Hex.encode
{-# INLINE encodeBase32hex #-}
decodeBase32hex :: ByteString -> Either String ByteString
decodeBase32hex bs
| C8.null bs = pure mempty
| otherwise = first (base32Err bs) . Base32Hex.decode . padTo 8 . C8.map toUpper $ bs
{-# INLINE decodeBase32hex #-}
encodeBase32hexupper :: ByteString -> AtBase "32xu"
encodeBase32hexupper = BaseN . dropPadding . Base32Hex.encode
{-# INLINE encodeBase32hexupper #-}
decodeBase32hexupper :: ByteString -> Either String ByteString
decodeBase32hexupper bs = first (base32Err bs) . Base32Hex.decode . padTo 8 $ bs
{-# INLINE decodeBase32hexupper #-}
encodeBase32hexpad :: ByteString -> AtBase "32xp"
encodeBase32hexpad = BaseN . C8.map toLower . Base32Hex.encode
{-# INLINE encodeBase32hexpad #-}
decodeBase32hexpad :: ByteString -> Either String ByteString
decodeBase32hexpad bs =
first (base32Err bs) . Base32Hex.decode . C8.map toUpper $ bs
{-# INLINE decodeBase32hexpad #-}
encodeBase32hexpadupper :: ByteString -> AtBase "32xpu"
encodeBase32hexpadupper = BaseN . Base32Hex.encode
{-# INLINE encodeBase32hexpadupper #-}
decodeBase32hexpadupper :: ByteString -> Either String ByteString
decodeBase32hexpadupper bs = first (base32Err bs) . Base32Hex.decode $ bs
{-# INLINE decodeBase32hexpadupper #-}
encodeBase32 :: ByteString -> AtBase "32"
encodeBase32 = BaseN . C8.map toLower . dropPadding . Base32.encode
{-# INLINE encodeBase32 #-}
decodeBase32 :: ByteString -> Either String ByteString
decodeBase32 bs =
first (base32Err bs) . Base32.decode . padTo 8 . C8.map toUpper $ bs
{-# INLINE decodeBase32 #-}
encodeBase32z :: ByteString -> AtBase "32z"
encodeBase32z = BaseN . Base32z.encode
{-# INLINE encodeBase32z #-}
decodeBase32z :: ByteString -> Either String ByteString
decodeBase32z = Base32z.decode . C8.map toLower
{-# INLINE decodeBase32z #-}
encodeBase32upper :: ByteString -> AtBase "32u"
encodeBase32upper = BaseN . dropPadding . Base32.encode
{-# INLINE encodeBase32upper #-}
decodeBase32upper :: ByteString -> Either String ByteString
decodeBase32upper bs = first (base32Err bs) . Base32.decode . padTo 8 $ bs
{-# INLINE decodeBase32upper #-}
encodeBase32pad :: ByteString -> AtBase "32p"
encodeBase32pad = BaseN . C8.map toLower . Base32.encode
{-# INLINE encodeBase32pad #-}
decodeBase32pad :: ByteString -> Either String ByteString
decodeBase32pad bs = first (base32Err bs) . Base32.decode . C8.map toUpper $ bs
{-# INLINE decodeBase32pad #-}
encodeBase32padupper :: ByteString -> AtBase "32pu"
encodeBase32padupper = BaseN . Base32.encode
{-# INLINE encodeBase32padupper #-}
decodeBase32padupper :: ByteString -> Either String ByteString
decodeBase32padupper bs = first (base32Err bs) . Base32.decode $ bs
{-# INLINE decodeBase32padupper #-}
base32Err :: ByteString -> (ByteString, ByteString) -> String
base32Err orig (x, invalid) = mconcat
[ "Decoded "
, "`", unpack orig, "`"
, " to "
, "`", unpack x, "`"
, " until invalid sequence: "
, "`", unpack invalid, "`"
]
encodeBase58flickr :: ByteString -> AtBase "58flickr"
encodeBase58flickr = BaseN . Base58.encodeBase58 Base58.flickrAlphabet
{-# INLINE encodeBase58flickr #-}
decodeBase58flickr :: ByteString -> Either String ByteString
decodeBase58flickr =
note "Invalid characters in Base58flickr string"
. Base58.decodeBase58 Base58.flickrAlphabet
{-# INLINE decodeBase58flickr #-}
encodeBase58btc :: ByteString -> AtBase "58btc"
encodeBase58btc = BaseN . Base58.encodeBase58 Base58.bitcoinAlphabet
{-# INLINE encodeBase58btc #-}
decodeBase58btc :: ByteString -> Either String ByteString
decodeBase58btc =
note "Invalid characters in Base58btc string"
. Base58.decodeBase58 Base58.bitcoinAlphabet
{-# INLINE decodeBase58btc #-}
encodeBase64pad :: ByteString -> AtBase "64p"
encodeBase64pad = BaseN . Base64.encode
{-# INLINE encodeBase64pad #-}
decodeBase64pad :: ByteString -> Either String ByteString
decodeBase64pad = Base64.decode
{-# INLINE decodeBase64pad #-}
encodeBase64url :: ByteString -> AtBase "64url"
encodeBase64url = BaseN . fst . C8.spanEnd (== '=') . Base64Url.encode
{-# INLINE encodeBase64url #-}
decodeBase64url :: ByteString -> Either String ByteString
decodeBase64url = Base64Url.decode . padTo 4
{-# INLINE decodeBase64url #-}
encodeBase64urlpad :: ByteString -> AtBase "64urlp"
encodeBase64urlpad = BaseN . Base64Url.encode
{-# INLINE encodeBase64urlpad #-}
decodeBase64urlpad :: ByteString -> Either String ByteString
decodeBase64urlpad = Base64Url.decode
{-# INLINE decodeBase64urlpad #-}
encodeAtBase :: Base b -> ByteString -> AtBase b
encodeAtBase Base2 = BaseN
encodeAtBase Base16 = encodeBase16
encodeAtBase Base64 = encodeBase64
encodeAtBase BaseIdentity = BaseN
encodeAtBase Base16upper = encodeBase16upper
encodeAtBase Base32hex = encodeBase32hex
encodeAtBase Base32hexupper = encodeBase32hexupper
encodeAtBase Base32hexpad = encodeBase32hexpad
encodeAtBase Base32hexpadupper = encodeBase32hexpadupper
encodeAtBase Base32 = encodeBase32
encodeAtBase Base32z = encodeBase32z
encodeAtBase Base32upper = encodeBase32upper
encodeAtBase Base32pad = encodeBase32pad
encodeAtBase Base32padupper = encodeBase32padupper
encodeAtBase Base58flickr = encodeBase58flickr
encodeAtBase Base58btc = encodeBase58btc
encodeAtBase Base64pad = encodeBase64pad
encodeAtBase Base64url = encodeBase64url
encodeAtBase Base64urlpad = encodeBase64urlpad
decodeBase16 :: ByteString -> Maybe ByteString
decodeBase16 = either (const Nothing) pure . decodeBase16Either
decodeBase16Either :: ByteString -> Either String ByteString
decodeBase16Either bs =
case Base16.decode bs of
(x, "") -> Right x
(x, invalid) -> Left . mconcat $
[ "Decoded: "
, "`", unpack x, "`"
, " until invalid sequence: "
, "`", unpack invalid, "`"
]
{-# INLINE decodeBase16Either #-}
decodeBase64 :: ByteString -> Maybe ByteString
decodeBase64 = either (const Nothing) pure . decodeBase64Either
decodeBase64Either :: ByteString -> Either String ByteString
decodeBase64Either = Base64.decode
{-# INLINE decodeBase64Either #-}
decodeBase64Lenient :: ByteString -> ByteString
decodeBase64Lenient = Base64.decodeLenient
{-# INLINE decodeBase64Lenient #-}
class DecodeBase (b :: Symbol) where
decodeAtBase :: proxy b -> ByteString -> Maybe ByteString
decodeAtBaseEither :: proxy b -> ByteString -> Either String ByteString
instance DecodeBase "id" where
decodeAtBase = const pure
decodeAtBaseEither = const pure
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "2" where
decodeAtBase = const pure
decodeAtBaseEither = const pure
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "16" where
decodeAtBase = const decodeBase16
decodeAtBaseEither = const decodeBase16Either
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "16u" where
decodeAtBase = const (hush . decodeBase16upper)
decodeAtBaseEither = const decodeBase16upper
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32" where
decodeAtBase = const (hush . decodeBase32)
decodeAtBaseEither = const decodeBase32
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32z" where
decodeAtBase = const (hush . decodeBase32z)
decodeAtBaseEither = const decodeBase32z
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32u" where
decodeAtBase = const (hush . decodeBase32upper)
decodeAtBaseEither = const decodeBase32upper
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32p" where
decodeAtBase = const (hush . decodeBase32pad)
decodeAtBaseEither = const decodeBase32pad
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32pu" where
decodeAtBase = const (hush . decodeBase32padupper)
decodeAtBaseEither = const decodeBase32padupper
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32x" where
decodeAtBase = const (hush . decodeBase32hex)
decodeAtBaseEither = const decodeBase32hex
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32xu" where
decodeAtBase = const (hush . decodeBase32hexupper)
decodeAtBaseEither = const decodeBase32hexupper
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32xp" where
decodeAtBase = const (hush . decodeBase32hexpad)
decodeAtBaseEither = const decodeBase32hexpad
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "32xpu" where
decodeAtBase = const (hush . decodeBase32hexpadupper)
decodeAtBaseEither = const decodeBase32hexpadupper
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "58btc" where
decodeAtBase = const (hush . decodeBase58btc)
decodeAtBaseEither = const decodeBase58btc
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "58flickr" where
decodeAtBase = const (hush . decodeBase58flickr)
decodeAtBaseEither = const decodeBase58flickr
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "64" where
decodeAtBase = const decodeBase64
decodeAtBaseEither = const decodeBase64Either
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "64p" where
decodeAtBase = const (hush . decodeBase64pad)
decodeAtBaseEither = const decodeBase64pad
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "64url" where
decodeAtBase = const (hush . decodeBase64url)
decodeAtBaseEither = const decodeBase64url
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
instance DecodeBase "64urlpad" where
decodeAtBase = const (hush . decodeBase64urlpad)
decodeAtBaseEither = const decodeBase64urlpad
{-# INLINE decodeAtBase #-}
{-# INLINE decodeAtBaseEither #-}
decode :: DecodeBase b => AtBase b -> ByteString
decode at = case decodeAtBaseEither at (encodedBytes at) of
Left e -> error $ "Impossible: invalid base encoding: " <> e
Right b -> b
validBase16 :: ByteString -> Maybe (AtBase "16")
validBase16 bs = BaseN bs <$ decodeBase16 bs
validBase16Either :: ByteString -> Either String (AtBase "16")
validBase16Either bs = second (const $ BaseN bs) $ decodeBase16Either bs
validBase16upper :: ByteString -> Maybe (AtBase "16u")
validBase16upper bs = BaseN bs <$ hush (decodeBase16upper bs)
validBase16upperEither :: ByteString -> Either String (AtBase "16u")
validBase16upperEither bs = second (const $ BaseN bs) $ decodeBase16upper bs
validBase32hex :: ByteString -> Maybe (AtBase "32x")
validBase32hex bs = BaseN bs <$ hush (decodeBase32hex bs)
validBase32hexEither :: ByteString -> Either String (AtBase "32x")
validBase32hexEither bs = second (const $ BaseN bs) $ decodeBase32hex bs
validBase32hexupper :: ByteString -> Maybe (AtBase "32xu")
validBase32hexupper bs = BaseN bs <$ hush (decodeBase32hexupper bs)
validBase32hexupperEither :: ByteString -> Either String (AtBase "32xu")
validBase32hexupperEither bs = second (const $ BaseN bs) $ decodeBase32hexupper bs
validBase32hexpad :: ByteString -> Maybe (AtBase "32xp")
validBase32hexpad bs = BaseN bs <$ hush (decodeBase32hexpad bs)
validBase32hexpadEither :: ByteString -> Either String (AtBase "32xp")
validBase32hexpadEither bs = second (const $ BaseN bs) $ decodeBase32hexpad bs
validBase32hexpadupper :: ByteString -> Maybe (AtBase "32xpu")
validBase32hexpadupper bs = BaseN bs <$ hush (decodeBase32hexpadupper bs)
validBase32hexpadupperEither :: ByteString -> Either String (AtBase "32xpu")
validBase32hexpadupperEither bs = second (const $ BaseN bs) $ decodeBase32hexpadupper bs
validBase32 :: ByteString -> Maybe (AtBase "32")
validBase32 bs = BaseN bs <$ hush (decodeBase32 bs)
validBase32Either :: ByteString -> Either String (AtBase "32")
validBase32Either bs = second (const $ BaseN bs) $ decodeBase32 bs
validBase32z :: ByteString -> Maybe (AtBase "32z")
validBase32z bs = BaseN bs <$ hush (decodeBase32z bs)
validBase32zEither :: ByteString -> Either String (AtBase "32z")
validBase32zEither bs = second (const $ BaseN bs) $ decodeBase32z bs
validBase32upper :: ByteString -> Maybe (AtBase "32u")
validBase32upper bs = BaseN bs <$ hush (decodeBase32upper bs)
validBase32upperEither :: ByteString -> Either String (AtBase "32u")
validBase32upperEither bs = second (const $ BaseN bs) $ decodeBase32upper bs
validBase32pad :: ByteString -> Maybe (AtBase "32p")
validBase32pad bs = BaseN bs <$ hush (decodeBase32pad bs)
validBase32padEither :: ByteString -> Either String (AtBase "32p")
validBase32padEither bs = second (const $ BaseN bs) $ decodeBase32pad bs
validBase32padupper :: ByteString -> Maybe (AtBase "32pu")
validBase32padupper bs = BaseN bs <$ hush (decodeBase32padupper bs)
validBase32padupperEither :: ByteString -> Either String (AtBase "32pu")
validBase32padupperEither bs = second (const $ BaseN bs) $ decodeBase32padupper bs
validBase58btc :: ByteString -> Maybe (AtBase "58btc")
validBase58btc bs = BaseN bs <$ hush (decodeBase58btc bs)
validBase58btcEither :: ByteString -> Either String (AtBase "58btc")
validBase58btcEither bs = second (const $ BaseN bs) $ decodeBase58btc bs
validBase58flickr :: ByteString -> Maybe (AtBase "58flickr")
validBase58flickr bs = BaseN bs <$ hush (decodeBase58flickr bs)
validBase58flickrEither :: ByteString -> Either String (AtBase "58flickr")
validBase58flickrEither bs = second (const $ BaseN bs) $ decodeBase58flickr bs
validBase64 :: ByteString -> Maybe (AtBase "64")
validBase64 bs = BaseN bs <$ decodeBase64 bs
validBase64Either :: ByteString -> Either String (AtBase "64")
validBase64Either bs = second (const $ BaseN bs) $ decodeBase64Either bs
validBase64pad :: ByteString -> Maybe (AtBase "64p")
validBase64pad bs = BaseN bs <$ hush (decodeBase64pad bs)
validBase64padEither :: ByteString -> Either String (AtBase "64p")
validBase64padEither bs = second (const $ BaseN bs) $ decodeBase64pad bs
validBase64url :: ByteString -> Maybe (AtBase "64url")
validBase64url bs = BaseN bs <$ hush (decodeBase64url bs)
validBase64urlEither :: ByteString -> Either String (AtBase "64url")
validBase64urlEither bs = second (const $ BaseN bs) $ decodeBase64url bs
validBase64urlpad :: ByteString -> Maybe (AtBase "64urlpad")
validBase64urlpad bs = BaseN bs <$ hush (decodeBase64urlpad bs)
validBase64urlpadEither :: ByteString -> Either String (AtBase "64urlpad")
validBase64urlpadEither bs = second (const $ BaseN bs) $ decodeBase64urlpad bs
class KnownSymbol b => ValidBase (b :: Symbol) where
validAtBase :: proxy b -> ByteString -> Maybe (AtBase b)
validAtBaseEither :: proxy b -> ByteString -> Either String (AtBase b)
instance ValidBase "id" where
validAtBase = const (pure . BaseN)
validAtBaseEither = const (pure . BaseN)
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "2" where
validAtBase = const (pure . BaseN)
validAtBaseEither = const (pure . BaseN)
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "16" where
validAtBase = const validBase16
validAtBaseEither = const validBase16Either
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "16u" where
validAtBase = const validBase16upper
validAtBaseEither = const validBase16upperEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32x" where
validAtBase = const validBase32hex
validAtBaseEither = const validBase32hexEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32xu" where
validAtBase = const validBase32hexupper
validAtBaseEither = const validBase32hexupperEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32xp" where
validAtBase = const validBase32hexpad
validAtBaseEither = const validBase32hexpadEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32xpu" where
validAtBase = const validBase32hexpadupper
validAtBaseEither = const validBase32hexpadupperEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32" where
validAtBase = const validBase32
validAtBaseEither = const validBase32Either
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32z" where
validAtBase = const validBase32z
validAtBaseEither = const validBase32zEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32u" where
validAtBase = const validBase32upper
validAtBaseEither = const validBase32upperEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32p" where
validAtBase = const validBase32pad
validAtBaseEither = const validBase32padEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "32pu" where
validAtBase = const validBase32padupper
validAtBaseEither = const validBase32padupperEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "58btc" where
validAtBase = const validBase58btc
validAtBaseEither = const validBase58btcEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "58flickr" where
validAtBase = const validBase58flickr
validAtBaseEither = const validBase58flickrEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "64" where
validAtBase = const validBase64
validAtBaseEither = const validBase64Either
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "64p" where
validAtBase = const validBase64pad
validAtBaseEither = const validBase64padEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "64url" where
validAtBase = const validBase64url
validAtBaseEither = const validBase64urlEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
instance ValidBase "64urlpad" where
validAtBase = const validBase64urlpad
validAtBaseEither = const validBase64urlpadEither
{-# INLINE validAtBase #-}
{-# INLINE validAtBaseEither #-}
validAndDecoded
:: DecodeBase b
=> proxy b
-> ByteString
-> Maybe (AtBase b, ByteString)
validAndDecoded at bs = (BaseN bs,) <$> decodeAtBase at bs
validAndDecodedEither
:: DecodeBase b
=> proxy b
-> ByteString
-> Either String (AtBase b, ByteString)
validAndDecodedEither at bs = (BaseN bs,) <$> decodeAtBaseEither at bs
encodedTextAtBase :: Base b -> Text -> AtBase b
encodedTextAtBase b = encodeAtBase b . encodeUtf8
{-# INLINE encodedTextAtBase #-}
encodedText :: AtBase b -> Text
encodedText (BaseN bs) = decodeLatin1 bs
{-# INLINE encodedText #-}
encodedTextBuilder :: AtBase b -> T.Builder
encodedTextBuilder = T.fromText . encodedText
{-# INLINE encodedTextBuilder #-}
format, formatAtBase :: Formatting.Format r (AtBase b -> r)
format = Formatting.later encodedTextBuilder
formatAtBase = format
{-# INLINE formatAtBase #-}
dropPadding :: ByteString -> ByteString
dropPadding = fst . C8.spanEnd (== '=')
{-# INLINE dropPadding #-}
padTo :: Int -> ByteString -> ByteString
padTo multipleof bs =
case C8.length bs `mod` multipleof of
0 -> bs
x -> mappend bs (C8.replicate (multipleof - x) '=')
note :: a -> Maybe b -> Either a b
note a = maybe (Left a) pure
hush :: Either a b -> Maybe b
hush = either (const Nothing) Just