content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE FlexibleInstances #-}
  
  
  {- | A module providing access to internals (in case you really need them).
  Can change at any time, though probably won't.
  -}
  module Fmt.Internal
  (
    -- * Classes
    FormatAsHex(..),
    FormatAsBase64(..),
  
    -- * Reexports
    module Fmt.Internal.Core,
    module Fmt.Internal.Formatters,
    module Fmt.Internal.Template,
    module Fmt.Internal.Tuple,
    module Fmt.Internal.Numeric,
    module Fmt.Internal.Generic,
  )
  where
  
  
  -- Text
  import qualified Data.Text.Encoding as T
  import qualified Data.Text.Lazy.Encoding as TL
  -- 'Buildable' and raw 'Builder' formatters
  import qualified Formatting.Internal.Raw as F
  -- Text 'Builder'
  import           Data.Text.Lazy.Builder hiding (fromString)
  -- Bytestring
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.Lazy as BSL
  -- Formatting bytestrings
  import qualified Data.ByteString.Builder         as BB
  import qualified Data.ByteString.Base64          as B64
  import qualified Data.ByteString.Base64.Lazy     as B64L
  import qualified Data.ByteString.Base64.URL      as B64U
  import qualified Data.ByteString.Base64.URL.Lazy as B64UL
  
  import Fmt.Internal.Core
  import Fmt.Internal.Formatters
  import Fmt.Internal.Template
  import Fmt.Internal.Tuple
  import Fmt.Internal.Numeric
  import Fmt.Internal.Generic
  
  -- $setup
  -- >>> import Fmt
  
  ----------------------------------------------------------------------------
  -- Hex
  ----------------------------------------------------------------------------
  
  class FormatAsHex a where
    {- |
  Format a number or bytestring as hex:
  
  >>> hexF 3635
  "e33"
  >>> hexF ("\0\50\63\80" :: BS.ByteString)
  "00323f50"
    -}
    hexF :: a -> Builder
  
  instance FormatAsHex BS.ByteString where
    hexF = fromLazyText . TL.decodeLatin1 . BB.toLazyByteString . BB.byteStringHex
  
  instance FormatAsHex BSL.ByteString where
    hexF = fromLazyText . TL.decodeLatin1 . BB.toLazyByteString . BB.lazyByteStringHex
  
  instance {-# OVERLAPPABLE #-} Integral a => FormatAsHex a where
    hexF i = sgn <> F.hex (abs i)
      where
        sgn = if i<0 then "-" else ""
  
  ----------------------------------------------------------------------------
  -- Base64
  ----------------------------------------------------------------------------
  
  class FormatAsBase64 a where
    {- |
  Convert a bytestring to base64:
  
  >>> base64F ("\0\50\63\80" :: BS.ByteString)
  "ADI/UA=="
    -}
    base64F :: a -> Builder
    {- |
  Convert a bytestring to base64url (a variant of base64 which omits @\/@ and
  thus can be used in URLs):
  
  >>> base64UrlF ("\0\50\63\80" :: BS.ByteString)
  "ADI_UA=="
    -}
    base64UrlF :: a -> Builder
  
  instance FormatAsBase64 BS.ByteString where
    base64F    = fromText . T.decodeLatin1 . B64.encode
    base64UrlF = fromText . T.decodeLatin1 . B64U.encode
  
  instance FormatAsBase64 BSL.ByteString where
    base64F    = fromLazyText . TL.decodeLatin1 . B64L.encode
    base64UrlF = fromLazyText . TL.decodeLatin1 . B64UL.encode
  