{-# LANGUAGE ScopedTypeVariables #-} module Data.Geometry.Geos.Raw.Serialize ( createReader , createWriter , createWktReader , createWktWriter , read , readHex , readWkt , write , writeHex , writeWkt ) where import Prelude hiding (read) import qualified Data.Geometry.Geos.Raw.Internal as I import Data.Geometry.Geos.Raw.Base import Data.Geometry.Geos.Raw.Geometry import Foreign import Foreign.C.String import Foreign.C.Types import qualified Data.ByteString.Char8 as BC newtype Reader = Reader { _unReader :: ForeignPtr I.GEOSWKBReader } newtype Writer = Writer { _unWriter :: ForeignPtr I.GEOSWKBWriter } newtype WktReader = WktReader { _unWktReader :: ForeignPtr I.GEOSWKTReader } newtype WktWriter = WktWriter { _unWktWriter :: ForeignPtr I.GEOSWKTWriter } createReader :: Geos Reader createReader = withGeos $ \h -> do ptr <- throwIfNull "Create Reader" $ I.geos_WKBReaderCreate h Reader <$> newForeignPtrEnv I.geos_WKBReaderDestroy h ptr createWktReader :: Geos WktReader createWktReader = withGeos $ \h -> do ptr <- throwIfNull "Create WKT Reader" $ I.geos_WKTReaderCreate h WktReader <$> newForeignPtrEnv I.geos_WKTReaderDestroy h ptr read_ :: (I.GEOSContextHandle_t -> Ptr I.GEOSWKBReader -> CString -> CSize -> IO (Ptr I.GEOSGeometry)) -> Reader -> BC.ByteString -> Geos (Maybe Geom) read_ f (Reader r) bs = withGeos readBlock where readBlock h = do ptr <- withForeignPtr r $ \rp -> BC.useAsCStringLen bs $ \(cs, l) -> f h rp cs $ fromIntegral l g <- wrapUpGeom h ptr pure g wrapUpGeom :: I.GEOSContextHandle_t -> Ptr I.GEOSGeometry -> IO (Maybe Geom) wrapUpGeom h ptr | ptr == nullPtr = pure Nothing | otherwise = Just . Geom <$> newForeignPtrEnv I.geos_GeomDestroy h ptr read :: Reader -> BC.ByteString -> Geos (Maybe Geom) read = readWkb readWkb :: Reader -> BC.ByteString -> Geos (Maybe Geom) readWkb = read_ I.geos_WKBReaderRead readHex :: Reader -> BC.ByteString -> Geos (Maybe Geom) readHex = read_ I.geos_WKBReaderReadHex readWkt :: WktReader -> BC.ByteString -> Geos (Maybe Geom) readWkt (WktReader r) bs = do withGeos $ \h -> do ptr <- withForeignPtr r $ \rp -> BC.useAsCString bs $ \cs -> I.geos_WKTReaderRead h rp cs g <- wrapUpGeom h ptr pure g createWriter :: Geos Writer createWriter = withGeos $ \h -> do ptr <- throwIfNull "CreateWriter" $ I.geos_WKBWriterCreate h I.geos_WKBWriterSetIncludeSRID h ptr $ fromBool True fp <- newForeignPtrEnv I.geos_WKBWriterDestroy h ptr return $ Writer fp createWktWriter :: Geos WktWriter createWktWriter = withGeos $ \h -> do ptr <- throwIfNull "CreateWktWriter" $ I.geos_WKTWriterCreate h fp <- newForeignPtrEnv I.geos_WKTWriterDestroy h ptr return $ WktWriter fp write_ :: Geometry a => (I.GEOSContextHandle_t -> Ptr I.GEOSWKBWriter -> Ptr I.GEOSGeometry -> Ptr CSize -> IO CString) -> Writer -> a -> Geos BC.ByteString write_ f (Writer w) g = withGeos $ \h -> do clen <- withForeignPtr w $ \wp -> withGeometry g $ \gp -> alloca $ \lp -> do cs <- f h wp gp lp vl <- fromIntegral `fmap` (peek lp) return (cs, vl) bs <- BC.packCStringLen clen return bs write :: Geometry a => Writer -> a -> Geos BC.ByteString write = write_ I.geos_WKBWriterWrite writeHex :: Geometry a => Writer -> a -> Geos BC.ByteString writeHex = write_ I.geos_WKBWriterWriteHex writeWkt :: Geometry a => WktWriter -> a -> Geos BC.ByteString writeWkt (WktWriter w) g = withGeos $ \h -> do wkt <- withForeignPtr w $ \wp -> withGeometry g $ \gp -> do cs <- I.geos_WKTWriterWrite h wp gp return cs bs <- BC.packCString wkt return bs