{-# LANGUAGE Safe #-}

{- |
Module                  : Relude.Extra.CallStack
Copyright               : (c) 2018-2023 Kowainik
SPDX-License-Identifier : MIT
Maintainer              : Kowainik <xrom.xkov@gmail.com>
Stability               : Stable
Portability             : Portable

Contains useful functions to work with GHC callstack.

@since 0.2.0
-}

module Relude.Extra.CallStack
    ( ownName
    , callerName
    ) where

import Relude

{- | This function returns the name of its caller function, but it requires
that the caller function has 'HasCallStack' constraint. Otherwise, it returns
@"<unknown>"@.

>>> foo :: HasCallStack => String; foo = ownName
>>> foo
"foo"
>>> bar :: HasCallStack => String; bar = foo
>>> bar
"foo"

@since 0.2.0
-}
ownName :: HasCallStack => String
ownName :: HasCallStack => String
ownName = case CallStack -> [(String, SrcLoc)]
getCallStack HasCallStack => CallStack
callStack of
    (String, SrcLoc)
_:(String, SrcLoc)
caller:[(String, SrcLoc)]
_ -> forall a b. (a, b) -> a
fst (String, SrcLoc)
caller
    [(String, SrcLoc)]
_          -> String
"<unknown>"

{- | This function returns the name of its caller of the caller function, but it
requires that the caller function and caller of the caller function have
'HasCallStack' constraint. Otherwise, it returns @"<unknown>"@. It's useful for
logging:

>>> log :: HasCallStack => String -> IO (); log s = putStrLn $ callerName ++ ":" ++ s
>>> greeting :: HasCallStack => IO (); greeting = log "Starting..." >> putStrLn "Hello!" >> log "Ending..."
>>> greeting
greeting:Starting...
Hello!
greeting:Ending...

@since 0.2.0
-}
callerName :: HasCallStack => String
callerName :: HasCallStack => String
callerName = case CallStack -> [(String, SrcLoc)]
getCallStack HasCallStack => CallStack
callStack of
    (String, SrcLoc)
_:(String, SrcLoc)
_:(String, SrcLoc)
caller:[(String, SrcLoc)]
_ -> forall a b. (a, b) -> a
fst (String, SrcLoc)
caller
    [(String, SrcLoc)]
_            -> String
"<unknown>"