{-# OPTIONS_HADDOCK hide #-}

module HsBindgen.Runtime.Internal.Bitfield (
    Bitfield(..)
  , defaultNarrow
  , signedExtend
  , unsignedExtend
  , loMask
  , hiMask
  , peekBitOffWidth
  , pokeBitOffWidth
) where

-- $setup
-- >>> import Data.Word
-- >>> import Numeric
-- >>> import Foreign.C.Types

import Data.Bits
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Word (Word16, Word32, Word64, Word8)
import Foreign.C.Types
import Foreign.Ptr
import Foreign.Storable

-- | Class for types which can be a bitfield in C struct.
--
-- The members converts to/from Word64 to make the use in the implementation of bitfields in @hs-bindgen@ easier.
-- We could not convert or have a smallest @WordN@ which would fit the type, but it complicates the usage for little benefit.
--
-- >>> let width = 5 :: Int
-- >>> extend (narrow (3 :: CSChar) width) width :: CSChar
-- 3
--
-- >>> let width = 5 :: Int
-- >>> extend (narrow (-7 :: CSChar) width) width :: CSChar
-- -7
--
-- overflow case, the result is undefined behavior:
--
-- >>> let width = 5 :: Int
-- >>> extend (narrow (-100 :: CSChar) width) width :: CSChar
-- -4
--
-- Development note: we could get away without a type-class using 'defaultNarrow', 'signedExtend' or 'unsignedExtend' directly.
-- However, we would need to encode the signedness of a target type somewhere anyway.
--
class Bitfield a where
    -- | Narrow the value so that only @n@ lowest bits are set.
    narrow :: a -> Int -> Word64
    default narrow :: Integral a => a -> Int -> Word64
    narrow = a -> Int -> Word64
forall a. Integral a => a -> Int -> Word64
defaultNarrow

    -- | Extend the value from only @n@ lowest bits representation.
    -- For example this may extend the sign for signed types.
    extend :: Word64 -> Int -> a

-- Instances for "Data.Int" signed integral types
instance Bitfield Int   where extend :: Word64 -> Int -> Int
extend = Word64 -> Int -> Int
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield Int8  where extend :: Word64 -> Int -> Int8
extend = Word64 -> Int -> Int8
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield Int16 where extend :: Word64 -> Int -> Int16
extend = Word64 -> Int -> Int16
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield Int32 where extend :: Word64 -> Int -> Int32
extend = Word64 -> Int -> Int32
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield Int64 where extend :: Word64 -> Int -> Int64
extend = Word64 -> Int -> Int64
forall a. Num a => Word64 -> Int -> a
signedExtend

-- Instances for "Data.Word" unsigned integral types
instance Bitfield Word   where extend :: Word64 -> Int -> Word
extend = Word64 -> Int -> Word
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield Word8  where extend :: Word64 -> Int -> Word8
extend = Word64 -> Int -> Word8
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield Word16 where extend :: Word64 -> Int -> Word16
extend = Word64 -> Int -> Word16
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield Word32 where extend :: Word64 -> Int -> Word32
extend = Word64 -> Int -> Word32
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield Word64 where extend :: Word64 -> Int -> Word64
extend = Word64 -> Int -> Word64
forall a. Num a => Word64 -> Int -> a
unsignedExtend

-- Instances for "Foreign.C.Types" signed integral types
instance Bitfield CChar      where extend :: Word64 -> Int -> CChar
extend = Word64 -> Int -> CChar
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CSChar     where extend :: Word64 -> Int -> CSChar
extend = Word64 -> Int -> CSChar
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CShort     where extend :: Word64 -> Int -> CShort
extend = Word64 -> Int -> CShort
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CInt       where extend :: Word64 -> Int -> CInt
extend = Word64 -> Int -> CInt
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CLong      where extend :: Word64 -> Int -> CLong
extend = Word64 -> Int -> CLong
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CPtrdiff   where extend :: Word64 -> Int -> CPtrdiff
extend = Word64 -> Int -> CPtrdiff
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CWchar     where extend :: Word64 -> Int -> CWchar
extend = Word64 -> Int -> CWchar
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CSigAtomic where extend :: Word64 -> Int -> CSigAtomic
extend = Word64 -> Int -> CSigAtomic
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CLLong     where extend :: Word64 -> Int -> CLLong
extend = Word64 -> Int -> CLLong
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CIntPtr    where extend :: Word64 -> Int -> CIntPtr
extend = Word64 -> Int -> CIntPtr
forall a. Num a => Word64 -> Int -> a
signedExtend
instance Bitfield CIntMax    where extend :: Word64 -> Int -> CIntMax
extend = Word64 -> Int -> CIntMax
forall a. Num a => Word64 -> Int -> a
signedExtend

-- Instances for "Foreign.C.Types" unsigned integral types
instance Bitfield CUChar   where extend :: Word64 -> Int -> CUChar
extend = Word64 -> Int -> CUChar
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CUShort  where extend :: Word64 -> Int -> CUShort
extend = Word64 -> Int -> CUShort
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CUInt    where extend :: Word64 -> Int -> CUInt
extend = Word64 -> Int -> CUInt
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CULong   where extend :: Word64 -> Int -> CULong
extend = Word64 -> Int -> CULong
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CSize    where extend :: Word64 -> Int -> CSize
extend = Word64 -> Int -> CSize
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CULLong  where extend :: Word64 -> Int -> CULLong
extend = Word64 -> Int -> CULLong
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CBool    where extend :: Word64 -> Int -> CBool
extend = Word64 -> Int -> CBool
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CUIntPtr where extend :: Word64 -> Int -> CUIntPtr
extend = Word64 -> Int -> CUIntPtr
forall a. Num a => Word64 -> Int -> a
unsignedExtend
instance Bitfield CUIntMax where extend :: Word64 -> Int -> CUIntMax
extend = Word64 -> Int -> CUIntMax
forall a. Num a => Word64 -> Int -> a
unsignedExtend

-- | Default 'narrow' implementation. Takes the lowest @n@ bits.
defaultNarrow :: Integral a => a -> Int -> Word64
defaultNarrow :: forall a. Integral a => a -> Int -> Word64
defaultNarrow a
x Int
n = a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Int -> Word64
forall a. (Num a, Bits a) => Int -> a
loMask Int
n

-- | Unsigned extend. Does nothing.
unsignedExtend :: Num a => Word64 -> Int -> a
unsignedExtend :: forall a. Num a => Word64 -> Int -> a
unsignedExtend Word64
x Int
_n = Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
x

-- | Signed extend, performs [sign extension](https://en.wikipedia.org/wiki/Sign_extension).
--
-- @n > 0@ (zero width bitfields are not allowed)
--
signedExtend :: Num a => Word64 -> Int -> a
signedExtend :: forall a. Num a => Word64 -> Int -> a
signedExtend Word64
x Int
n
    | Word64
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
b Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0 = Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
x -- no sign, just convert
    | Bool
otherwise    = Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> a) -> Word64 -> a
forall a b. (a -> b) -> a -> b
$ Word64
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64 -> Word64
forall a. Bits a => a -> a
complement (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL Word64
b Int
1 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1) -- extend the sign
  where
    b :: Word64
b = Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL Word64
1 (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)

-- | Generate a low mask
--
-- >>> map (flip showBin "" . loMask @Word16) [0, 1, 2, 5, 8, 16]
-- ["0","1","11","11111","11111111","1111111111111111"]
--
loMask :: (Num a, Bits a) => Int -> a
loMask :: forall a. (Num a, Bits a) => Int -> a
loMask Int
n = a -> Int -> a
forall a. Bits a => a -> Int -> a
unsafeShiftL a
1 Int
n a -> a -> a
forall a. Num a => a -> a -> a
- a
1

-- | Generate a high mask
--
-- >>> map (flip showBin "" . hiMask @Word16) [0, 1, 2, 5, 8, 16]
-- ["1111111111111111","1111111111111110","1111111111111100","1111111111100000","1111111100000000","0"]
--
hiMask :: (Num a, Bits a) => Int -> a
hiMask :: forall a. (Num a, Bits a) => Int -> a
hiMask Int
n = a -> a
forall a. Bits a => a -> a
complement (Int -> a
forall a. (Num a, Bits a) => Int -> a
loMask Int
n)

-------------------------------------------------------------------------------
-- Storable
-------------------------------------------------------------------------------

-- | Peek a 'Bitfield' from a memory.
--
-- We assume that offset and width are such that we can read & write the whole
-- bitfield with one (read or write) operation. This means that bitfields cannot
-- span multiple 'Word64's. At the extreme, if the width is 64, the offset can
-- only be a multiple of 64.
--
-- Note: the implementation may perform unaligned reads.
peekBitOffWidth :: Bitfield a => Ptr b -> Int -> Int -> IO a
peekBitOffWidth :: forall a b. Bitfield a => Ptr b -> Int -> Int -> IO a
peekBitOffWidth Ptr b
ptr Int
off Int
width
    | (Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
8 = do
        Word8
w <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word8
        a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$! Word64 -> Int -> a
forall a. Bitfield a => Word64 -> Int -> a
extend (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR Word8
w (Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
forall a. (Num a, Bits a) => Int -> a
loMask Int
width)) Int
width

    | (Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
16 = do
        Word16
w <- Ptr b -> Int -> IO Word16
forall b. Ptr b -> Int -> IO Word16
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word16
        a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$! Word64 -> Int -> a
forall a. Bitfield a => Word64 -> Int -> a
extend (Word16 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
unsafeShiftR Word16
w (Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Int -> Word16
forall a. (Num a, Bits a) => Int -> a
loMask Int
width)) Int
width

    | (Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
32 = do
        Word32
w <- Ptr b -> Int -> IO Word32
forall b. Ptr b -> Int -> IO Word32
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word32
        a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$! Word64 -> Int -> a
forall a. Bitfield a => Word64 -> Int -> a
extend (Word32 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
unsafeShiftR Word32
w (Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Int -> Word32
forall a. (Num a, Bits a) => Int -> a
loMask Int
width)) Int
width

    | (Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
64 = do
        Word64
w <- Ptr b -> Int -> IO Word64
forall b. Ptr b -> Int -> IO Word64
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word64
        a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$! Word64 -> Int -> a
forall a. Bitfield a => Word64 -> Int -> a
extend (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
w (Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Int -> Word64
forall a. (Num a, Bits a) => Int -> a
loMask Int
width) Int
width

    | Bool
otherwise = String -> IO a
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO a) -> String -> IO a
forall a b. (a -> b) -> a -> b
$ String
"peekBitOffWidth _ " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
off String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Ptr b -> String
forall a. Show a => a -> String
show Ptr b
ptr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": too wide"

-- As far as I can tell there are no more clever bit fiddling way to do this:
-- See e.g. https://godbolt.org/z/cfcdc1eKd
-- for @ptr->y = y@; we get
--
-- @
-- mov     ecx, dword ptr [rbp - 12]
-- mov     rax, qword ptr [rbp - 8]
-- mov     dl, cl
-- mov     cl, byte ptr [rax]
-- and     dl, 7
-- shl     dl, 2
-- and     cl, -29
-- or      cl, dl
-- mov     byte ptr [rax], cl
-- @
--
-- 7 is mask 0b111 for three bits (unsigned int y : 3) (it's used by 'narrow')
-- -29 is another mask @1111111111100011@, which is @complement (unsafeShiftL (loMask width) ...)@ in the pokeBitOffWidth
--
pokeBitOffWidth :: Bitfield a => Ptr b -> Int -> Int -> a -> IO ()
pokeBitOffWidth :: forall a b. Bitfield a => Ptr b -> Int -> Int -> a -> IO ()
pokeBitOffWidth Ptr b
ptr Int
off Int
width a
x
    | (Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
8 = do
        Word8
w <- Ptr b -> Int -> IO Word8
forall b. Ptr b -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word8
        let x' :: Word8
x' = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Int -> Word64
forall a. Bitfield a => a -> Int -> Word64
narrow a
x Int
width) :: Word8
        let mask :: Word8
mask = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL (Int -> Word8
forall a. (Num a, Bits a) => Int -> a
loMask Int
width) (Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)
            x'' :: Word8
x''  = Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftL Word8
x'             (Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)

        Ptr b -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x7 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) ((Word8
w Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8 -> Word8
forall a. Bits a => a -> a
complement Word8
mask) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
x'')

    | (Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
16 = do
        Word16
w <- Ptr b -> Int -> IO Word16
forall b. Ptr b -> Int -> IO Word16
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word16
        let x' :: Word16
x' = Word64 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Int -> Word64
forall a. Bitfield a => a -> Int -> Word64
narrow a
x Int
width) :: Word16
        let mask :: Word16
mask = Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
unsafeShiftL (Int -> Word16
forall a. (Num a, Bits a) => Int -> a
loMask Int
width) (Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)
            x'' :: Word16
x''  = Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
unsafeShiftL Word16
x'             (Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)

        Ptr b -> Int -> Word16 -> IO ()
forall b. Ptr b -> Int -> Word16 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0xf Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) ((Word16
w Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.&. Word16 -> Word16
forall a. Bits a => a -> a
complement Word16
mask) Word16 -> Word16 -> Word16
forall a. Bits a => a -> a -> a
.|. Word16
x'')

    | (Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
32 = do
        Word32
w <- Ptr b -> Int -> IO Word32
forall b. Ptr b -> Int -> IO Word32
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word32
        let x' :: Word32
x' = Word64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Int -> Word64
forall a. Bitfield a => a -> Int -> Word64
narrow a
x Int
width) :: Word32
        let mask :: Word32
mask = Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
unsafeShiftL (Int -> Word32
forall a. (Num a, Bits a) => Int -> a
loMask Int
width) (Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)
            x'' :: Word32
x''  = Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
unsafeShiftL Word32
x'             (Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)

        Ptr b -> Int -> Word32 -> IO ()
forall b. Ptr b -> Int -> Word32 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x1f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) ((Word32
w Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32 -> Word32
forall a. Bits a => a -> a
complement Word32
mask) Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
x'')

    | (Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
width Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
64 = do
        Word64
w <- Ptr b -> Int -> IO Word64
forall b. Ptr b -> Int -> IO Word64
forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) :: IO Word64
        let x' :: Word64
x' = a -> Int -> Word64
forall a. Bitfield a => a -> Int -> Word64
narrow a
x Int
width :: Word64
        let mask :: Word64
mask = Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL (Int -> Word64
forall a. (Num a, Bits a) => Int -> a
loMask Int
width) (Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)
            x'' :: Word64
x''  = Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL Word64
x'             (Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off)

        Ptr b -> Int -> Word64 -> IO ()
forall b. Ptr b -> Int -> Word64 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr b
ptr (Int -> Int
forall a. Bits a => a -> a
complement Int
0x3f Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
off) ((Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64 -> Word64
forall a. Bits a => a -> a
complement Word64
mask) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
x'')

    | Bool
otherwise = String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"pokeBitOffWidth _ " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
off String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Ptr b -> String
forall a. Show a => a -> String
show Ptr b
ptr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" _: too wide"