content: ----------------------------------------------------------------------------
  -- |
  -- Module      :  Data.Emacs.Module.Doc
  -- Copyright   :  (c) Sergey Vinokurov 2022
  -- License     :  Apache-2.0 (see LICENSE)
  -- Maintainer  :  serg.foo@gmail.com
  --
  -- Defines type that provides function's documentation that would be visible
  -- in Emacs.
  ----------------------------------------------------------------------------
  
  {-# LANGUAGE MagicHash #-}
  
  module Data.Emacs.Module.Doc
    ( Doc
    , mkLiteralDoc
    , mkTextDoc
    , useDocAsCString
    ) where
  
  import Data.String
  import Data.Text (Text)
  import Data.Text qualified as T
  import Data.Text.Foreign qualified as T
  import Foreign.C.String
  import GHC.Exts
  
  data Doc
    = StaticDoc Addr#
    | DynamicDoc !Text
  
  instance Show Doc where
    show = \case
      DynamicDoc x   -> show x
      StaticDoc addr -> show (unpackCString# addr)
  
  instance IsString Doc where
    {-# INLINE fromString #-}
    fromString = mkStringDoc
  
  mkStringDoc :: String -> Doc
  mkStringDoc = mkTextDoc . T.pack
  
  {-# INLINE [0] mkStringDoc #-}
  
  {-# RULES
  "Doc string literal" forall s .
     mkStringDoc (unpackCString# s) = mkLiteralDoc s
   #-}
  
  -- | Indended to be used with unboxed string literals like this
  --
  -- @
  -- mkLiteralDoc "foo"#
  -- @
  {-# INLINE mkLiteralDoc #-}
  mkLiteralDoc :: Addr# -> Doc
  mkLiteralDoc = StaticDoc
  
  -- | Turn abritrary bytestring into 'Doc'.
  {-# INLINE mkTextDoc #-}
  mkTextDoc :: Text -> Doc
  mkTextDoc = DynamicDoc
  
  {-# INLINE useDocAsCString #-}
  useDocAsCString :: Doc -> (CString -> IO a) -> IO a
  useDocAsCString doc f = case doc of
    StaticDoc addr -> f (Ptr addr)
    DynamicDoc str -> T.withCString str f
  
  