unix-simple-0.1.0.0: src/CString.hs
module CString
( CString
, CStr(..)
, useCStr
, fromBuilder
, toBuilder
) where
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Internal as BS
import qualified Data.ByteString.Lazy as LBS
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr
import Zhp
-- | wrapper around a nul-terminated C style string; the pointer points to the
-- beginning of the string.
--
-- Users of the library will mostly not use this directly, instead using CString.
newtype CStr = CStr (Ptr CChar)
-- | A string for passing to C api functions. The C-compatible form is computed
-- lazily; it will not be forced until the string is passed to a C API function.
-- Internally, this is stored as a 'BB.Builder' with no trailing nul, so
-- performance characteristics are mostly the same, only requiring a copy when
-- first passing the string to an API function.
data CString = CString
{ bytes :: BB.Builder
, fptr :: ForeignPtr CChar
}
instance Semigroup CString where
x <> y = fromBuilder (toBuilder x <> toBuilder y)
instance Monoid CString where
mempty = fromBuilder mempty
-- | Convert a 'BB.Builder' to a CString. The builder should not have a nul
-- terminator; it will be added.
fromBuilder :: BB.Builder -> CString
fromBuilder builder = CString
{ bytes = builder
, fptr =
let bs = LBS.toStrict $ BB.toLazyByteString (builder <> BB.word8 0)
(ptr, off, _len) = BS.toForeignPtr bs
in
plusForeignPtr ptr off
}
-- | Extract a bytestring builder for the string. Does not include the nul
-- terminator. O(1).
toBuilder :: CString -> BB.Builder
toBuilder = bytes
-- | Use the raw pointer underlying the 'CString'.
useCStr :: CString -> (CStr -> IO a) -> IO a
useCStr str use =
withForeignPtr (fptr str) $ \ptr -> use (CStr ptr)
instance IsString CString where
fromString = fromBuilder . BB.stringUtf8