module Data.Packed.Packed (
    Packed (..),
    unsafeToPacked,
    unsafeToPacked',
    fromPacked,
    unsafeCastPacked,
    duplicate,
    getPtr,
) where

import Control.DeepSeq
import Data.ByteString (copy)
import Data.ByteString.Internal
import Data.Kind (Type)
import Foreign.Ptr
import GHC.Exts (Ptr (Ptr))
import GHC.ForeignPtr

-- | A buffer that contains one or more packed (i.e. serialised) values.
-- The order of the values in the buffer is defined by the 'l' type list
newtype Packed (l :: [Type]) = Packed ByteString

instance NFData (Packed a) where
    rnf :: Packed a -> ()
rnf Packed a
packed = Packed a -> ByteString
forall (a :: [*]). Packed a -> ByteString
fromPacked Packed a
packed ByteString -> () -> ()
forall a b. a -> b -> b
`Prelude.seq` ()

-- | Duplicates a 'Packed' buffer. The returned 'Packed' is independent from the source one.
duplicate :: Packed a -> Packed a
duplicate :: forall (a :: [*]). Packed a -> Packed a
duplicate (Packed ByteString
bs) = ByteString -> Packed a
forall (l :: [*]). ByteString -> Packed l
Packed (ByteString -> Packed a) -> ByteString -> Packed a
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
copy ByteString
bs

{-# INLINE unsafeToPacked #-}

-- | UNSAFE: Casts a generic 'ByteString' into a 'Data.Packed.Needs'
unsafeToPacked :: ByteString -> Packed a
unsafeToPacked :: forall (l :: [*]). ByteString -> Packed l
unsafeToPacked = ByteString -> Packed a
forall (l :: [*]). ByteString -> Packed l
Packed

{-# INLINE fromPacked #-}

-- | Extracts the raw buffer from a 'Data.Packed' value
fromPacked :: Packed a -> ByteString
fromPacked :: forall (a :: [*]). Packed a -> ByteString
fromPacked (Packed ByteString
bs) = ByteString
bs

{-# INLINE unsafeCastPacked #-}

-- | UNSAFE: Casts a typed 'Packed' value into another 'Packed' value of another type
unsafeCastPacked :: Packed a -> Packed b
unsafeCastPacked :: forall (a :: [*]) (b :: [*]). Packed a -> Packed b
unsafeCastPacked = ByteString -> Packed b
forall (l :: [*]). ByteString -> Packed l
unsafeToPacked (ByteString -> Packed b)
-> (Packed a -> ByteString) -> Packed a -> Packed b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Packed a -> ByteString
forall (a :: [*]). Packed a -> ByteString
fromPacked

unsafeToPacked' :: Ptr a -> Int -> Packed b
unsafeToPacked' :: forall a (b :: [*]). Ptr a -> Int -> Packed b
unsafeToPacked' (Ptr Addr#
addr) Int
l = ByteString -> Packed b
forall (l :: [*]). ByteString -> Packed l
Packed (ForeignPtr Word8 -> Int -> ByteString
BS (Addr# -> ForeignPtrContents -> ForeignPtr Word8
forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr Addr#
addr ForeignPtrContents
FinalPtr) Int
l)

getPtr :: Packed a -> Ptr b
getPtr :: forall (a :: [*]) b. Packed a -> Ptr b
getPtr Packed a
p = let BS ForeignPtr Word8
fptr Int
_ = Packed a -> ByteString
forall (a :: [*]). Packed a -> ByteString
fromPacked Packed a
p in Ptr Word8 -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr (Ptr Word8 -> Ptr b) -> Ptr Word8 -> Ptr b
forall a b. (a -> b) -> a -> b
$ ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtr ForeignPtr Word8
fptr