{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances #-} module LLVM.Internal.String where import LLVM.Prelude import Control.Arrow import Control.Monad.AnyCont import Control.Monad.IO.Class import Control.Exception (finally) import Foreign.C (CString, CChar) import Foreign.Ptr import Foreign.Storable (Storable) import Foreign.Marshal.Alloc as F.M (alloca, free) import LLVM.Internal.FFI.LLVMCTypes import LLVM.Internal.Coding import qualified Data.ByteString as BS import qualified LLVM.Internal.FFI.ShortByteString as SBS import qualified Data.ByteString.Unsafe as BS import qualified Data.ByteString.UTF8 as BSUTF8 newtype UTF8ByteString = UTF8ByteString { utf8Bytes :: BS.ByteString } instance (Monad e) => EncodeM e String UTF8ByteString where encodeM = return . UTF8ByteString . BSUTF8.fromString instance (Monad d) => DecodeM d String UTF8ByteString where decodeM = return . BSUTF8.toString . utf8Bytes instance (MonadAnyCont IO e) => EncodeM e String CString where encodeM s = anyContToM (BS.unsafeUseAsCString . utf8Bytes =<< encodeM (s ++ "\0")) instance (MonadAnyCont IO e) => EncodeM e ByteString CString where encodeM s = anyContToM (BS.useAsCString s) instance (MonadAnyCont IO e) => EncodeM e ShortByteString CString where encodeM s = anyContToM (SBS.useAsCString s) instance (Integral i, MonadAnyCont IO e) => EncodeM e String (Ptr CChar, i) where encodeM s = anyContToM ((. (. second fromIntegral)) $ BS.useAsCStringLen . utf8Bytes =<< encodeM s) instance (Integral i, MonadAnyCont IO e) => EncodeM e ByteString (Ptr CChar, i) where encodeM s = anyContToM (\cont -> BS.useAsCStringLen s (\(ptr, len) -> cont (ptr, fromIntegral len))) instance (Integral i, MonadAnyCont IO e) => EncodeM e ShortByteString (Ptr CChar, i) where encodeM s = anyContToM (\cont -> SBS.useAsCStringLen s (\(ptr, len) -> cont (ptr, fromIntegral len))) instance (MonadIO d) => DecodeM d String CString where decodeM = decodeM . UTF8ByteString <=< liftIO . BS.packCString instance (MonadIO d) => DecodeM d ByteString CString where decodeM = liftIO . BS.packCString instance (MonadIO d) => DecodeM d ShortByteString CString where decodeM = liftIO . SBS.packCString instance (MonadIO d) => DecodeM d String (OwnerTransfered CString) where decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s) instance (MonadIO d) => DecodeM d ByteString (OwnerTransfered CString) where decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s) instance (MonadIO d) => DecodeM d ShortByteString (OwnerTransfered CString) where decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s) instance (MonadIO d, DecodeM IO s (OwnerTransfered CString)) =>DecodeM d s (Ptr (OwnerTransfered CString)) where decodeM = liftIO . decodeM <=< peek instance (Integral i, MonadIO d) => DecodeM d String (Ptr CChar, i) where decodeM = decodeM . UTF8ByteString <=< liftIO . BS.packCStringLen . second fromIntegral instance (Integral i, MonadIO d) => DecodeM d BS.ByteString (Ptr CChar, i) where decodeM = liftIO . BS.packCStringLen . second fromIntegral instance (Integral i, MonadIO d) => DecodeM d ShortByteString (Ptr CChar, i) where decodeM = liftIO . SBS.packCStringLen . second fromIntegral instance (Integral i, Storable i, MonadIO d, DecodeM d s (CString, i)) => DecodeM d s (Ptr i -> IO CString) where decodeM f = decodeM =<< (liftIO $ F.M.alloca $ \p -> (,) `liftM` f p `ap` peek p) instance (Monad e, EncodeM e String c) => EncodeM e (Maybe String) (NothingAsEmptyString c) where encodeM = liftM NothingAsEmptyString . encodeM . fromMaybe ""