fmt-0.6.2.0: lib/Fmt/Internal.hs
{-# 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