{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}

module Bluefin.Internal.Prim where

import Bluefin.Internal
  ( Eff,
    Effects,
    Handle,
    HandleD (MkHandleD),
    OneWayCoercibleHandle,
    effIO,
    makeOp,
    unsafeProvideIO,
    (:&),
    type (<:),
  )
import Bluefin.Internal.OneWayCoercible
  ( OneWayCoercible (..),
    unsafeOneWayCoercible,
  )
import Control.Monad.Primitive qualified as P
import GHC.Exts (State#)
import Unsafe.Coerce (unsafeCoerce)

data Prim (e :: Effects) = UnsafeMkPrim
  deriving (HandleD Prim
HandleD Prim -> Handle Prim
forall (h :: Effects -> *). HandleD h -> Handle h
$chandleImpl :: HandleD Prim
handleImpl :: HandleD Prim
Handle) via OneWayCoercibleHandle Prim

data PrimStateEff (es :: Effects)

instance (e <: es) => OneWayCoercible (Prim e) (Prim es) where
  oneWayCoercibleImpl :: OneWayCoercibleD (Prim e) (Prim es)
oneWayCoercibleImpl = OneWayCoercibleD (Prim e) (Prim es)
forall {k} (a :: k) (b :: k). OneWayCoercibleD a b
unsafeOneWayCoercible

runPrim ::
  (forall e. Prim e -> Eff (e :& es) r) ->
  -- | ͘
  Eff es r
runPrim :: forall (es :: Effects) r.
(forall (e :: Effects). Prim e -> Eff (e :& es) r) -> Eff es r
runPrim forall (e :: Effects). Prim e -> Eff (e :& es) r
k = Eff (es :& es) r -> Eff es r
forall (e :: Effects) r. Eff (e :& e) r -> Eff e r
makeOp (Prim es -> Eff (es :& es) r
forall (e :: Effects). Prim e -> Eff (e :& es) r
k Prim es
forall (e :: Effects). Prim e
UnsafeMkPrim)

type StateM s a = State# s -> (# State# s, a #)

unsafeCoerceStateM :: forall s1 s2 a. StateM s1 a -> StateM s2 a
unsafeCoerceStateM :: forall s1 s2 a. StateM s1 a -> StateM s2 a
unsafeCoerceStateM = StateM s1 a -> StateM s2 a
forall a b. a -> b
unsafeCoerce

primitive ::
  forall e1 es a.
  (e1 <: es) =>
  Prim e1 ->
  (State# (PrimStateEff e1) -> (# State# (PrimStateEff e1), a #)) ->
  -- | ͘
  Eff es a
primitive :: forall (e1 :: Effects) (es :: Effects) a.
(e1 <: es) =>
Prim e1
-> (State# (PrimStateEff e1) -> (# State# (PrimStateEff e1), a #))
-> Eff es a
primitive Prim e1
UnsafeMkPrim State# (PrimStateEff e1) -> (# State# (PrimStateEff e1), a #)
k = (forall (e :: Effects). IOE e -> Eff (e :& es) a) -> Eff es a
forall (es :: Effects) a.
(forall (e :: Effects). IOE e -> Eff (e :& es) a) -> Eff es a
unsafeProvideIO ((forall (e :: Effects). IOE e -> Eff (e :& es) a) -> Eff es a)
-> (forall (e :: Effects). IOE e -> Eff (e :& es) a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \IOE e
io ->
  IOE e -> IO a -> Eff (e :& es) a
forall (e :: Effects) (es :: Effects) a.
(e <: es) =>
IOE e -> IO a -> Eff es a
effIO
    IOE e
io
    (forall (m :: * -> *) a.
PrimMonad m =>
(State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
P.primitive @IO (forall s1 s2 a. StateM s1 a -> StateM s2 a
unsafeCoerceStateM @(PrimStateEff e1) @P.RealWorld State# (PrimStateEff e1) -> (# State# (PrimStateEff e1), a #)
k))