packages feed

gbnet-hs-0.2.2.0: src/GBNet/ZeroCopy.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- |
-- Module      : GBNet.ZeroCopy
-- Description : Zero-copy vector mutation via ST
--
-- Internal module providing zero-overhead in-place mutation of immutable
-- vectors. Safety is enforced through two mechanisms:
--
--   1. __ST rank-2 type__: the @forall s@ prevents the mutable vector
--      from escaping the callback — compiler-enforced, not convention.
--
--   2. __Module opacity__: this module is internal. All buffer types
--      (@SequenceBuffer@, @SentPacketBuffer@, etc.) are opaque, so
--      external code cannot access the raw vectors.
--
-- The @unsafeThaw@\/@unsafeFreeze@ pair are pointer casts (zero memcpy),
-- giving C-level mutation performance with Haskell's type-level guarantees.
module GBNet.ZeroCopy
  ( -- * Unboxed vectors
    zeroCopyMutateU,
    zeroCopyMutateU',

    -- * Boxed vectors
    zeroCopyMutate,
    zeroCopyMutate',
  )
where

import Control.Monad.ST (ST, runST)
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
import Data.Vector.Unboxed (Unbox)
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM

-- | Zero-copy mutation of an unboxed vector.
--
-- @unsafeThaw@\/@unsafeFreeze@ are pointer casts — zero allocation.
-- The @forall s@ prevents the mutable vector from escaping the callback.
zeroCopyMutateU ::
  forall a.
  (Unbox a) =>
  VU.Vector a ->
  (forall s. VUM.MVector s a -> ST s ()) ->
  VU.Vector a
zeroCopyMutateU vec action = runST $ do
  mv <- VU.unsafeThaw vec
  action mv
  VU.unsafeFreeze mv
{-# INLINE zeroCopyMutateU #-}

-- | Zero-copy mutation of an unboxed vector, returning a result.
zeroCopyMutateU' ::
  forall a b.
  (Unbox a) =>
  VU.Vector a ->
  (forall s. VUM.MVector s a -> ST s b) ->
  (VU.Vector a, b)
zeroCopyMutateU' vec action = runST $ do
  mv <- VU.unsafeThaw vec
  result <- action mv
  frozen <- VU.unsafeFreeze mv
  return (frozen, result)
{-# INLINE zeroCopyMutateU' #-}

-- | Zero-copy mutation of a boxed vector.
--
-- @unsafeThaw@\/@unsafeFreeze@ are pointer casts — zero allocation.
-- The @forall s@ prevents the mutable vector from escaping the callback.
zeroCopyMutate ::
  forall a.
  V.Vector a ->
  (forall s. MV.MVector s a -> ST s ()) ->
  V.Vector a
zeroCopyMutate vec action = runST $ do
  mv <- V.unsafeThaw vec
  action mv
  V.unsafeFreeze mv
{-# INLINE zeroCopyMutate #-}

-- | Zero-copy mutation of a boxed vector, returning a result.
zeroCopyMutate' ::
  forall a b.
  V.Vector a ->
  (forall s. MV.MVector s a -> ST s b) ->
  (V.Vector a, b)
zeroCopyMutate' vec action = runST $ do
  mv <- V.unsafeThaw vec
  result <- action mv
  frozen <- V.unsafeFreeze mv
  return (frozen, result)
{-# INLINE zeroCopyMutate' #-}