content: module Jhc.ForeignPtr(
      ForeignPtr(),
      newPlainForeignPtr_,
      newForeignPtr_,
      mallocPlainForeignPtrAlignBytes,
      mallocForeignPtrAlignBytes,
      unsafeForeignPtrToPtr,
      castForeignPtr,
      touchForeignPtr
      ) where
  
  import Jhc.Addr
  import Jhc.IO
  import Jhc.Prim.Prim
  import Jhc.Prim.Rts
  import Jhc.Type.Basic
  import Jhc.Basics
  import Jhc.Order
  
  type FinalizerPtr  a = FunPtr (Ptr a -> IO ())
  
  -- not Addr_ because we need to make sure it is allocated in a real heap
  -- location. The actual ForeignPtr heap location may contain more than the
  -- single BitsPtr_ argument.
  data ForeignPtr a = FP BitsPtr_
  
  instance Eq (ForeignPtr a) where
      p == q  =  unsafeForeignPtrToPtr p == unsafeForeignPtrToPtr q
  
  instance Ord (ForeignPtr a) where
      compare p q  =  compare (unsafeForeignPtrToPtr p) (unsafeForeignPtrToPtr q)
  
  -- | This function creates a plain ForeignPtr from a Ptr, a plain foreignptr
  -- may not have finalizers associated with it, hence this function may be pure.
  newPlainForeignPtr_ :: Ptr a -> ForeignPtr a
  newPlainForeignPtr_  (Ptr (Addr_ addr)) = FP addr
  
  newForeignPtr_ :: Ptr a -> IO (ForeignPtr a)
  newForeignPtr_ ptr = fromUIO $ \w ->
      case gc_new_foreignptr ptr w of
          (# w', bp #) -> (# w', fromBang_ bp #)
  
  -- | This function is similar to 'mallocForeignPtrAlignBytes', except that the
  -- internally an optimised ForeignPtr representation with no finalizer is used.
  -- Attempts to add a finalizer will cause the program to abort.
  mallocPlainForeignPtrAlignBytes
      :: Int -- ^ alignment in bytes, must be power of 2. May be zero.
      -> Int -- ^ size to allocate in bytes.
      -> IO (ForeignPtr a)
  mallocPlainForeignPtrAlignBytes align size = fromUIO $ \w ->
      case gc_malloc_foreignptr (int2word align) (int2word size) False w of
          (# w', bp #) -> (# w', fromBang_ bp #)
  
  -- | Allocate memory of the given size and alignment that will automatically be
  -- reclaimed. Any Finalizers that are attached to this will run before the
  -- memory is freed.
  mallocForeignPtrAlignBytes
      :: Int -- ^ alignment in bytes, must be power of 2. May be zero.
      -> Int -- ^ size to allocate in bytes.
      -> IO (ForeignPtr a)
  mallocForeignPtrAlignBytes align size = fromUIO $ \w ->
      case gc_malloc_foreignptr (int2word align) (int2word size) True w of
          (# w', bp #) -> (# w', fromBang_ bp #)
  
  foreign import jhc_context ccall gc_malloc_foreignptr
      :: Word     -- alignment in words
      -> Word     -- size in words
      -> Bool     -- false for plain foreignptrs, true for ones with finalizers.
      -> UIO (Bang_ (ForeignPtr a))
  
  foreign import jhc_context ccall gc_new_foreignptr ::
      Ptr a -> UIO (Bang_ (ForeignPtr a))
  
  foreign import unsafe ccall gc_add_foreignptr_finalizer
      :: Bang_ (ForeignPtr a)
      -> FinalizerPtr a
      -> IO ()
  
  unsafeForeignPtrToPtr :: ForeignPtr a -> Ptr a
  unsafeForeignPtrToPtr (FP x) = Ptr (Addr_ x)
  
  touchForeignPtr :: ForeignPtr a -> IO ()
  touchForeignPtr x = fromUIO_ (touch_ x)
  
  castForeignPtr :: ForeignPtr a -> ForeignPtr b
  castForeignPtr x = unsafeCoerce x
  
  foreign import primitive touch_ :: ForeignPtr a -> UIO_
  foreign import primitive "B2B" int2word :: Int -> Word
  foreign import primitive unsafeCoerce :: a -> b
  