{-# LANGUAGE FlexibleInstances #-}

module Formatting.FromBuilder
  ( FromBuilder(..)
  , formatted
  ) where

import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as TL
import Formatting.Internal (Format (..))

-- $setup
-- >>> import qualified Data.Text.Lazy as TL (Text)
-- >>> import qualified Data.Text.Lazy.IO as TL
-- >>> import qualified Data.Text as T (Text)
-- >>> import qualified Data.Text.IO as T
-- >>> import Formatting ((%))
-- >>> import Formatting.Formatters (int)
-- >>> :set -XOverloadedStrings
-- >>> :set -XTypeApplications

-- | Anything that can be created from a 'Builder'.
--   This class makes it easier to add formatting to other API's.
--   See 'formatted' for some examples of this class in action.
class FromBuilder a where
  fromBuilder :: Builder -> a

instance FromBuilder Builder where
  fromBuilder :: Builder -> Builder
fromBuilder = Builder -> Builder
forall a. a -> a
id
  {-# INLINE fromBuilder #-}

instance FromBuilder TL.Text where
  fromBuilder :: Builder -> Text
fromBuilder = Builder -> Text
TL.toLazyText
  {-# INLINE fromBuilder #-}

instance FromBuilder T.Text where
  fromBuilder :: Builder -> Text
fromBuilder = Text -> Text
TL.toStrict (Text -> Text) -> (Builder -> Text) -> Builder -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
TL.toLazyText
  {-# INLINE fromBuilder #-}

instance FromBuilder [Char] where
  fromBuilder :: Builder -> [Char]
fromBuilder = Text -> [Char]
TL.unpack (Text -> [Char]) -> (Builder -> Text) -> Builder -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Text
TL.toLazyText
  {-# INLINE fromBuilder #-}

-- | Makes it easy to add formatting to any api that is expecting a builder,
--   a strict or lazy text, or a string.
--   It is essentially (flip runFormat), but with a more generous type due to
--   the typeclass.
--
--   For example:
--   >>> formatted TL.putStr ("x is: " % int % "\n") 7
--   x is: 7
--   >>> formatted T.putStr ("x is: " % int % "\n") 7
--   x is: 7
--   >>> formatted (id @TL.Text) ("x is: " % int % "\n") 7
--   "x is: 7\n"
--   >>> formatted (id @T.Text) ("x is: " % int % "\n") 7
--   "x is: 7\n"
formatted :: FromBuilder t => (t -> o) -> Format o a -> a
formatted :: forall t o a. FromBuilder t => (t -> o) -> Format o a -> a
formatted t -> o
k Format o a
f = Format o a -> (Builder -> o) -> a
forall r a. Format r a -> (Builder -> r) -> a
runFormat Format o a
f (t -> o
k (t -> o) -> (Builder -> t) -> Builder -> o
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> t
forall a. FromBuilder a => Builder -> a
fromBuilder)