{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE LambdaCase #-}
module Haskus.Memory.Ptr
( Pointer (..)
, AnyPointer (..)
, RawPtr
, FinPtr
, PtrI
, PtrM
, PtrIF
, PtrMF
, isNullPtr
, nullPtrI
, nullPtrM
, indexPtr
, distancePtr
, withPtr
, withFinalizedPtr
, allocFinalizedPtr
, allocPtr
, freePtr
, P.FunPtr
, P.nullFunPtr
, P.castPtrToFunPtr
, P.castFunPtrToPtr
, P.WordPtr
, P.wordPtrToPtr
, P.ptrToWordPtr
)
where
import qualified Foreign.Ptr as P
import qualified Foreign.Marshal.Alloc as P
import qualified Foreign.ForeignPtr as FP
import qualified Foreign.ForeignPtr.Unsafe as FP
import Haskus.Memory.Property
import Haskus.Utils.Monad
import Haskus.Utils.Flow
data Pointer (mut :: Mutability) (fin :: Finalization) where
PtrI :: {-# UNPACK #-} !RawPtr -> PtrI
PtrM :: {-# UNPACK #-} !RawPtr -> PtrM
PtrIF :: {-# UNPACK #-} !FinPtr -> {-# UNPACK #-} !Int -> PtrIF
PtrMF :: {-# UNPACK #-} !FinPtr -> {-# UNPACK #-} !Int -> PtrMF
type RawPtr = P.Ptr ()
type FinPtr = FP.ForeignPtr ()
type PtrI = Pointer 'Immutable 'NotFinalized
type PtrM = Pointer 'Mutable 'NotFinalized
type PtrIF = Pointer 'Immutable 'Finalized
type PtrMF = Pointer 'Mutable 'Finalized
newtype AnyPointer = AnyPointer (forall mut fin . Pointer mut fin)
instance Show (Pointer mut fin) where
show = \case
PtrI p -> show p
PtrM p -> show p
PtrIF p o -> show (fToR p `P.plusPtr` o)
PtrMF p o -> show (fToR p `P.plusPtr` o)
fToR :: FinPtr -> RawPtr
fToR = FP.unsafeForeignPtrToPtr
{-# SPECIALIZE INLINE isNullPtr :: PtrI -> Bool #-}
{-# SPECIALIZE INLINE isNullPtr :: PtrM -> Bool #-}
{-# SPECIALIZE INLINE isNullPtr :: PtrIF -> Bool #-}
{-# SPECIALIZE INLINE isNullPtr :: PtrMF -> Bool #-}
isNullPtr :: Pointer mut fin -> Bool
isNullPtr = \case
PtrI p -> p == P.nullPtr
PtrM p -> p == P.nullPtr
PtrIF p 0 -> fToR p == P.nullPtr
PtrIF _ _ -> False
PtrMF p 0 -> fToR p == P.nullPtr
PtrMF _ _ -> False
nullPtrI :: PtrI
nullPtrI = PtrI P.nullPtr
nullPtrM :: PtrM
nullPtrM = PtrM P.nullPtr
{-# SPECIALIZE INLINE indexPtr :: PtrI -> Int -> PtrI #-}
{-# SPECIALIZE INLINE indexPtr :: PtrM -> Int -> PtrM #-}
{-# SPECIALIZE INLINE indexPtr :: PtrIF -> Int -> PtrIF #-}
{-# SPECIALIZE INLINE indexPtr :: PtrMF -> Int -> PtrMF #-}
indexPtr :: Pointer mut fin -> Int -> Pointer mut fin
indexPtr ptr i = case ptr of
PtrI p -> PtrI (p `P.plusPtr` i)
PtrM p -> PtrM (p `P.plusPtr` i)
PtrIF p o -> PtrIF p (o+i)
PtrMF p o -> PtrMF p (o+i)
{-# SPECIALIZE INLINE distancePtr :: PtrI -> PtrI -> Int #-}
{-# SPECIALIZE INLINE distancePtr :: PtrM -> PtrM -> Int #-}
{-# SPECIALIZE INLINE distancePtr :: PtrI -> PtrM -> Int #-}
{-# SPECIALIZE INLINE distancePtr :: PtrM -> PtrI -> Int #-}
distancePtr :: Pointer mut0 fin0 -> Pointer mut1 fin1 -> Int
distancePtr p1 p2 = P.minusPtr p1' p2' + o2 - o1
where
dec :: Pointer mut fin -> (RawPtr,Int)
dec = \case
PtrI p -> (p,0)
PtrM p -> (p,0)
PtrIF p o -> (fToR p,o)
PtrMF p o -> (fToR p,o)
(p1',o1) = dec p1
(p2',o2) = dec p2
{-# INLINABLE withFinalizedPtr #-}
withFinalizedPtr :: (MonadInIO m) => Pointer mut 'Finalized -> (Pointer mut 'NotFinalized -> m b) -> m b
withFinalizedPtr ptr f = case ptr of
PtrIF p o -> liftWith (FP.withForeignPtr p) <| \r ->
f (PtrI (r `P.plusPtr` o))
PtrMF p o -> liftWith (FP.withForeignPtr p) <| \r ->
f (PtrM (r `P.plusPtr` o))
{-# INLINABLE withPtr #-}
withPtr :: (MonadInIO m) => Pointer mut fin -> (Pointer mut 'NotFinalized -> m b) -> m b
withPtr ptr f = case ptr of
PtrI _ -> f ptr
PtrM _ -> f ptr
PtrIF p o -> liftWith (FP.withForeignPtr p) <| \r ->
f (PtrI (r `P.plusPtr` o))
PtrMF p o -> liftWith (FP.withForeignPtr p) <| \r ->
f (PtrM (r `P.plusPtr` o))
allocFinalizedPtr :: MonadIO m => Word -> m PtrMF
allocFinalizedPtr = liftIO . fmap (`PtrMF` 0) . FP.mallocForeignPtrBytes . fromIntegral
allocPtr :: MonadIO m => Word -> m PtrM
allocPtr = liftIO . fmap PtrM . P.mallocBytes . fromIntegral
{-# SPECIALIZE INLINE freePtr :: MonadIO m => PtrI -> m () #-}
{-# SPECIALIZE INLINE freePtr :: MonadIO m => PtrM -> m () #-}
freePtr :: MonadIO m => Pointer mut 'NotFinalized -> m ()
freePtr = \case
PtrI p -> liftIO (P.free p)
PtrM p -> liftIO (P.free p)