content: {-# language ScopedTypeVariables #-}
  {-# language TypeApplications #-}
  {-# language FlexibleContexts #-}
  {-# language ConstraintKinds #-}
  {-# language TypeFamilies #-}
  {-# language Trustworthy #-}
  -- |
  -- Copyright :  (c) 2019 Edward Kmett
  -- License   :  BSD-2-Clause OR Apache-2.0
  -- Maintainer:  Edward Kmett <ekmett@gmail.com>
  -- Stability :  experimental
  -- Portability: non-portable
  --
  module Foreign.Const.Ptr
  ( ConstPtr
  , constPtr
  , APtr
  
  -- * const-agnostic operations
  , peekAt
  , peekAtElemOff
  , peekAtByteOff
  
  -- * const preserving operations
  , minusAPtr
  , castAPtr
  , plusAPtr
  , alignAPtr
  
  -- * operations returning const pointers
  , nullConstPtr
  , castConstPtr
  , plusConstPtr
  , alignConstPtr
    ) where
  
  import Data.Coerce
  import Data.Type.Coercion
  import Foreign.Ptr
  import Foreign.Storable
  
  import Data.Const.Unsafe
  
  constPtr :: APtr p => p a -> ConstPtr a
  constPtr = constant
  {-# inline constPtr #-}
  
  peekAt :: forall p a. (Storable a, APtr p) => p a -> IO a
  peekAt = gcoerceWith (unsafePtrCoercion @p @a) (coerce (peek @a))
  {-# inline peekAt #-}
  
  peekAtElemOff :: forall p a. (Storable a, APtr p) => p a -> Int -> IO a
  peekAtElemOff = gcoerceWith (unsafePtrCoercion @p @a) $ coerce (peekElemOff @a)
  {-# inline peekAtElemOff #-}
  
  peekAtByteOff :: forall p a b. (Storable a, APtr p) => p b -> Int -> IO a
  peekAtByteOff = gcoerceWith (unsafePtrCoercion @p @b) $ coerce (peekByteOff @a @b)
  {-# inline peekAtByteOff #-}
  
  nullConstPtr :: ConstPtr a 
  nullConstPtr = ConstPtr nullPtr
  {-# inline nullConstPtr #-}
  
  castAPtr :: forall p a b. APtr p => p a -> p b
  castAPtr = gcoerceWith (unsafePtrCoercion @p @a) $ gcoerceWith (unsafePtrCoercion @p @b) $ coerce (castPtr @a @b)
  {-# inline castAPtr #-}
  
  castConstPtr :: forall p a b. APtr p => p a -> ConstPtr b
  castConstPtr = gcoerceWith (unsafePtrCoercion @p @a) $ coerce (castPtr @a @b)
  {-# inline castConstPtr #-}
  
  plusAPtr :: forall p a b. APtr p => p a -> Int -> p b
  plusAPtr = gcoerceWith (unsafePtrCoercion @p @a) $ gcoerceWith (unsafePtrCoercion @p @b) $ coerce (plusPtr @a @b)
  {-# inline plusAPtr #-}
  
  plusConstPtr :: forall p a b. APtr p => p a -> Int -> ConstPtr b
  plusConstPtr = gcoerceWith (unsafePtrCoercion @p @a) $ coerce (plusPtr @a @b)
  {-# inline plusConstPtr #-}
  
  alignAPtr :: forall p a. APtr p => p a -> Int -> p a
  alignAPtr = gcoerceWith (unsafePtrCoercion @p @a) $ coerce (alignPtr @a)
  {-# inline alignAPtr #-}
  
  alignConstPtr :: forall p a. APtr p => p a -> Int -> ConstPtr a
  alignConstPtr = gcoerceWith (unsafePtrCoercion @p @a) $ coerce (alignPtr @a)
  {-# inline alignConstPtr #-}
  
  minusAPtr :: forall p q a b. (APtr p, APtr q) => p a -> q b -> Int
  minusAPtr = gcoerceWith (unsafePtrCoercion @p @a) $ gcoerceWith (unsafePtrCoercion @q @b) $ coerce (minusPtr @a @b)
  {-# inline minusAPtr #-}
  