packages feed

libclang-bindings-0.1.0.0: src/Clang/Internal/CXString.hs

{-# OPTIONS_GHC -Wno-orphans #-}

-- | Dealing with @CXString@
--
-- This has no exports: the Haskell representation of @CXString@ is 'Text'.
module Clang.Internal.CXString () where

import Control.Exception
import Data.Text (Text)
import Data.Text qualified as Text
import Foreign
import Foreign.C
import GHC.Ptr (Ptr (..))

import Clang.Internal.ByValue
import Clang.Internal.ConstPtr (ConstPtr (unConstPtr))
import Clang.LowLevel.Core.Instances ()
import Clang.LowLevel.Core.Structs
import Clang.LowLevel.FFI

{-------------------------------------------------------------------------------
  Translation to bytestrings

  TODO <https://github.com/well-typed/libclang-bindings/issues/70>

  We could consider trying to deduplicate.
-------------------------------------------------------------------------------}

-- | @libclang@ uses UTF-8 internally
instance Preallocate Text where
  type Writing Text = W CXString_

  preallocate :: (W CXString_ -> IO b) -> IO (Text, b)
  preallocate allocStr =
      bracket
          (preallocate allocStr)
          (clang_disposeString . fst) $ \(str, b) -> do
        cstr@(Ptr addr) <- clang_getCString str
        if cstr == nullPtr then
          return (Text.empty, b)
        else do
          let !t = Text.unpackCString# addr
          return (t, b)

{-------------------------------------------------------------------------------
  Low-level bindings

  <https://clang.llvm.org/doxygen/group__CINDEX__STRING.html>
-------------------------------------------------------------------------------}

-- | A character string.
--
-- The 'CXString' type is used to return strings from the interface when the
-- ownership of that string might differ from one call to the next. Use
-- 'clang_getCString' to retrieve the string data and, once finished with the
-- string data, call 'clang_disposeString' to free the string.
--
-- <https://clang.llvm.org/doxygen/structCXString.html>
newtype CXString = CXString (OnHaskellHeap CXString_)
  deriving newtype (LivesOnHaskellHeap, Preallocate)

-- | Retrieve the character data associated with the given string.
--
-- We use @capi@ together with 'ConstPtr' here to avoid a compiler warning
-- about qualifying the @const@-ness of @const char *@ (see "Clang.Internal.ConstPtr").
--
-- <https://clang.llvm.org/doxygen/group__CINDEX__STRING.html#gabe1284209a3cd35c92e61a31e9459fe7>
clang_getCString :: CXString -> IO CString
clang_getCString str = unConstPtr <$> onHaskellHeap str wrap_getCString

-- | Free the given string.
--
-- <https://clang.llvm.org/doxygen/group__CINDEX__STRING.html#gaeff715b329ded18188959fab3066048f>
clang_disposeString :: CXString -> IO ()
clang_disposeString str = onHaskellHeap str $ wrap_disposeString