{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
{-# language DeriveGeneric #-}
{-# language DeriveDataTypeable #-}
module Foreign.Ptr.Diff
( Diff(..)
, inv
, next, prev
, (.*)
, advance
, DiffTorsor(..)
, peekDiffOff
, pokeDiffOff
) where
import Control.Category
import Control.Monad.IO.Class
import Data.Coerce
import Data.Data (Data)
import Foreign.ForeignPtr
import Foreign.ForeignPtr.Unsafe
import Foreign.Ptr
import Foreign.Storable
import GHC.Generics
import Prelude hiding (id,(.))
newtype Diff a b = Diff { getDiff :: Int }
deriving (Eq,Ord,Show,Read,Data,Generic)
instance Category Diff where
id = Diff 0
{-# inline id #-}
Diff a . Diff b = Diff (a + b)
{-# inline (.) #-}
(.*) :: Int -> Diff a a -> Diff a a
n .* Diff a = Diff (n*a)
{-# inline (.*) #-}
infixr 6 .*
inv :: Diff a b -> Diff b a
inv (Diff a) = Diff (negate a)
{-# inline inv #-}
next :: forall a. Storable a => Diff a a
next = Diff (sizeOf @a undefined)
{-# inline next #-}
prev :: Storable a => Diff a a
prev = inv next
{-# inline prev #-}
advance :: Storable a => Int -> Diff a a
advance n = n .* next
{-# inline advance #-}
class DiffTorsor t where
act :: Diff a b -> t a -> t b
diff :: t b -> t a -> Diff a b
instance DiffTorsor Ptr where
act = coerce (flip plusPtr)
diff = coerce minusPtr
{-# inline act #-}
{-# inline diff #-}
instance DiffTorsor FunPtr where
act d p = castPtrToFunPtr $ act d (castFunPtrToPtr p)
diff p q = diff (castFunPtrToPtr p) (castFunPtrToPtr q)
{-# inline act #-}
{-# inline diff #-}
instance DiffTorsor ForeignPtr where
act = coerce (flip plusForeignPtr)
diff p q = diff (unsafeForeignPtrToPtr p) (unsafeForeignPtrToPtr q)
{-# inline act #-}
{-# inline diff #-}
peekDiffOff :: (MonadIO m, Storable b) => Ptr a -> Diff a b -> m b
peekDiffOff p (Diff d) = liftIO $ peekByteOff p d
{-# inline peekDiffOff #-}
pokeDiffOff :: (MonadIO m, Storable b) => Ptr a -> Diff a b -> b -> m ()
pokeDiffOff p (Diff d) a = liftIO $ pokeByteOff p d a
{-# inline pokeDiffOff #-}