-- | Pointers to bitfields
--
-- This module is intended to be imported qualified.
--
-- > import HsBindgen.Runtime.Prelude
-- > import HsBindgen.Runtime.BitfieldPtr qualified as BitfieldPtr
module HsBindgen.Runtime.BitfieldPtr (
    BitfieldPtr(BitfieldPtr)
  , peek
  , poke
  ) where

import Data.Kind
import Foreign.Ptr

import HsBindgen.Runtime.Internal.Bitfield as Bitfield

-- | A pointer to a bit-field of a C object
type BitfieldPtr :: Type -> Type
type role BitfieldPtr nominal
-- The constructor is unsafe because the offset must be normalized (modulo 8
-- bits).
data BitfieldPtr a = UnsafeBitfieldPtr {
      forall a. BitfieldPtr a -> Ptr a
_ptr    :: Ptr a
      -- | The offset (in number of bits) of the bit-field from the pointer
    , forall a. BitfieldPtr a -> Int
_offset :: Int
      -- | The width (in number of bits) of the bit-field
    , forall a. BitfieldPtr a -> Int
_width  :: Int
    }

{-# COMPLETE BitfieldPtr #-}
pattern BitfieldPtr :: Ptr a -> Int -> Int -> BitfieldPtr a
pattern $bBitfieldPtr :: forall a. Ptr a -> Int -> Int -> BitfieldPtr a
$mBitfieldPtr :: forall {r} {a}.
BitfieldPtr a -> (Ptr a -> Int -> Int -> r) -> ((# #) -> r) -> r
BitfieldPtr p o w <- UnsafeBitfieldPtr p o w where
  BitfieldPtr Ptr a
p Int
o Int
w = Ptr a -> Int -> Int -> BitfieldPtr a
forall a. Ptr a -> Int -> Int -> BitfieldPtr a
UnsafeBitfieldPtr (Ptr a
p Ptr a -> Int -> Ptr a
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
nBytes) Int
o' Int
w
    where (Int
nBytes, Int
o') = Int
o Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
8

{-# INLINE peek #-}
-- | Read from a bit-field using a pointer
peek :: Bitfield a => BitfieldPtr a -> IO a
peek :: forall a. Bitfield a => BitfieldPtr a -> IO a
peek (BitfieldPtr Ptr a
p Int
o Int
w) = Ptr a -> Int -> Int -> IO a
forall a b. Bitfield a => Ptr b -> Int -> Int -> IO a
Bitfield.peekBitOffWidth Ptr a
p Int
o Int
w

{-# INLINE poke #-}
-- | Write to a bit-field using a pointer
poke :: Bitfield a => BitfieldPtr a -> a -> IO ()
poke :: forall a. Bitfield a => BitfieldPtr a -> a -> IO ()
poke (BitfieldPtr Ptr a
p Int
o Int
w) = Ptr a -> Int -> Int -> a -> IO ()
forall a b. Bitfield a => Ptr b -> Int -> Int -> a -> IO ()
Bitfield.pokeBitOffWidth Ptr a
p Int
o Int
w