content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE QuasiQuotes       #-}
  
  -- | Benchmarks for @fmt@ library.
  
  module Main where
  
  import           Control.DeepSeq         (NFData)
  import           Data.Monoid             ((<>))
  import           Data.String.Interpolate (i)
  import           Data.Text               (Text)
  import qualified Data.Text               as T
  import           Fmt                     ((+|), (|+), format)
  import           Formatting              (Format, formatToString, int, sformat, stext,
                                            string, (%))
  import           Text.Printf             (printf)
  
  import           Criterion               (Benchmark, bench, bgroup, nf)
  import           Criterion.Main          (defaultMain)
  
  ----------------------------------------------------------------------------
  -- Format utility functions
  ----------------------------------------------------------------------------
  
  -- Shorter alias for @formatToString@.
  fs :: Format String a -> a
  fs = formatToString
  
  tshow :: Show a => a -> Text
  tshow x = T.pack (show x)
  
  ----------------------------------------------------------------------------
  -- Benchmarks utility functions
  ----------------------------------------------------------------------------
  
  bGenericStringGroup :: NFData s => String -> a -> [(String, a -> s)] -> Benchmark
  bGenericStringGroup sTag benchObj =
      bgroup sTag . map (\(tag, howToFmt) -> bench tag (nf howToFmt benchObj))
  {-# INLINE bGenericStringGroup #-}
  
  bTextGroup :: a -> [(String, a -> Text)] -> Benchmark
  bTextGroup = bGenericStringGroup "text"
  {-# INLINE bTextGroup #-}
  
  bStringGroup :: a -> [(String, a -> String)] -> Benchmark
  bStringGroup = bGenericStringGroup "string"
  {-# INLINE bStringGroup #-}
  
  -- Function for convenience instead of using manual @(,)@.
  taggedB :: String -> (a -> b) -> (String, a -> b)
  taggedB = (,)
  
  ----------------------------------------------------------------------------
  -- Benchmakrs themselves
  ----------------------------------------------------------------------------
  
  main :: IO ()
  main = defaultMain
    [ bgroup "simple"
      [ bTextGroup (1 :: Int, 2 :: Int)
        [ taggedB "fmt" $
            \(a,b) -> "hello "+|a|+" world "+|b|+""
        , taggedB "fmt old-style" $
            \(a,b) -> format "hello {} world {}" a b :: Text
        , taggedB "formatting" $
            \(a,b) -> sformat ("hello "%int%" world "%int) a b
        , taggedB "interpolate" $
            \(a,b) -> T.pack [i|hello #{a} world #{b}|]
        , taggedB "show" $
            \(a,b) -> "hello " <> tshow a <> " world " <> tshow b
        , taggedB "printf" $
            \(a,b) -> T.pack $ printf "hello %d world %d" a b
        ]
      , bStringGroup (1 :: Int, 2 :: Int)
        [ taggedB "fmt" $
            \(a,b) -> "hello "+|a|+" world "+|b|+""
        , taggedB "fmt old-style" $
            \(a,b) -> format "hello {} world {}" a b :: String
        , taggedB "formatting" $
            \(a,b) -> fs ("hello "%int%" world "%int) a b
        , taggedB "interpolate" $
            \(a,b) -> [i|hello #{a} world #{b}|]
        , taggedB "show" $
            \(a,b) -> "hello " ++ show a ++ " world " ++ show b
        , taggedB "printf" $
            \(a,b) -> printf "hello %d world %d" a b
        ]
      ]
  
    , bgroup "readme"
      [ bTextGroup (9 :: Int, "Beijing" :: Text)
        [ taggedB "fmt" $
            \(n,city) -> "There are "+|n|+" million bicycles in "+|city|+"."
        , taggedB "fmt old-style" $
            \(n,city) -> format "There are {} million bicycles in {}." n city :: Text
        , taggedB "formatting" $
            \(n,city) -> sformat ("There are "%int%" million bicycles in "%stext%".") n city
        , taggedB "interpolate" $
            \(n,city) -> T.pack [i|There are #{n} million bicycles in #{city}.|]
        , taggedB "show" $
            \(n,city) -> "There are " <> tshow n <> " million bicycles in " <> city <> "."
        , taggedB "printf" $
            \(n,city) -> T.pack $ printf "There are %d million bicycles in %s." n city
        ]
      , bStringGroup (9 :: Int, "Beijing" :: String)
        [ taggedB "fmt" $
            \(n,city) -> "There are "+|n|+" million bicycles in "+|city|+"."
        , taggedB "fmt old-style" $
            \(n,city) -> format "There are {} million bicycles in {}." n city :: String
        , taggedB "formatting" $
            \(n,city) -> fs ("There are "%int%" million bicycles in "%string%".") n city
        , taggedB "interpolate" $
            \(n,city) -> [i|There are #{n} million bicycles in #{city}.|]
        , taggedB "show" $
            \(n,city) -> "There are " ++ show n ++ " million bicycles in " ++ city ++ "."
        , taggedB "printf" $
            \(n,city) -> printf "There are %d million bicycles in %s." n city
        ]
      ]
    ]
  