{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedNewtypes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}

module Control.Concurrent.DivideConquer.Utils.OnceChan.Linear.Unlifted (
  Sink#,
  Source#,
  new#,
  put#,
  take#,
) where

import Control.Monad.Borrow.Pure.Lifetime.Token
import Control.Monad.Borrow.Pure.Lifetime.Token.Unsafe (
  LinearOnly (..),
  LinearOnlyWitness (..),
 )
import GHC.Exts qualified as GHC
import Prelude.Linear
import Unsafe.Linear qualified as Unsafe

newtype Source# a = Source# (GHC.MVar# GHC.RealWorld a)

newtype Sink# a = Sink# (GHC.MVar# GHC.RealWorld a)

type role Source# representational

type role Sink# nominal

new# :: Linearly %1 -> (# Sink# a, Source# a #)
{-# NOINLINE new# #-}
new# :: forall a. Linearly %1 -> (# Sink# a, Source# a #)
new# = (Linearly %1 -> (# Sink# a, Source# a #))
-> Linearly %1 -> (# Sink# a, Source# a #)
forall a. a -> a
GHC.noinline ((Linearly %1 -> (# Sink# a, Source# a #))
 -> Linearly %1 -> (# Sink# a, Source# a #))
-> (Linearly %1 -> (# Sink# a, Source# a #))
-> Linearly
%1 -> (# Sink# a, Source# a #)
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ (Linearly -> (# Sink# a, Source# a #))
%1 -> Linearly %1 -> (# Sink# a, Source# a #)
forall a b (p :: Multiplicity) (x :: Multiplicity).
(a %p -> b) %1 -> a %x -> b
Unsafe.toLinear ((Linearly -> (# Sink# a, Source# a #))
 %1 -> Linearly %1 -> (# Sink# a, Source# a #))
-> (Linearly -> (# Sink# a, Source# a #))
%1 -> Linearly
%1 -> (# Sink# a, Source# a #)
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ \Linearly
_ ->
  (State# RealWorld -> (# Sink# a, Source# a #))
-> (# Sink# a, Source# a #)
forall o. (State# RealWorld -> o) -> o
GHC.runRW# \State# RealWorld
s ->
    case State# RealWorld -> (# State# RealWorld, MVar# RealWorld a #)
forall d a. State# d -> (# State# d, MVar# d a #)
GHC.newMVar# State# RealWorld
s of
      (# State# RealWorld
_, !MVar# RealWorld a
v #) -> (# MVar# RealWorld a -> Sink# a
forall a. MVar# RealWorld a -> Sink# a
Sink# MVar# RealWorld a
v, MVar# RealWorld a -> Source# a
forall a. MVar# RealWorld a -> Source# a
Source# MVar# RealWorld a
v #)

take# :: Source# a %1 -> a
{-# INLINE take# #-}
take# :: forall a. Source# a %1 -> a
take# = (Source# a %1 -> a) -> Source# a %1 -> a
forall a. a -> a
GHC.noinline ((Source# a %1 -> a) -> Source# a %1 -> a)
-> (Source# a %1 -> a) -> Source# a %1 -> a
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ (Source# a -> a) %1 -> Source# a %1 -> a
forall a b (p :: Multiplicity) (x :: Multiplicity).
(a %p -> b) %1 -> a %x -> b
Unsafe.toLinear \(Source# MVar# RealWorld a
mv) ->
  (State# RealWorld -> a) -> a
forall o. (State# RealWorld -> o) -> o
GHC.runRW# \State# RealWorld
s ->
    case MVar# RealWorld a -> State# RealWorld -> (# State# RealWorld, a #)
forall d a. MVar# d a -> State# d -> (# State# d, a #)
GHC.takeMVar# MVar# RealWorld a
mv State# RealWorld
s of
      (# State# RealWorld
_, !a
a #) -> a
a

put# :: Sink# a %1 -> a %1 -> ()
{-# NOINLINE put# #-}
put# :: forall a. Sink# a %1 -> a %1 -> ()
put# = (Sink# a %1 -> a %1 -> ()) -> Sink# a %1 -> a %1 -> ()
forall a. a -> a
GHC.noinline ((Sink# a %1 -> a %1 -> ()) -> Sink# a %1 -> a %1 -> ())
-> (Sink# a %1 -> a %1 -> ()) -> Sink# a %1 -> a %1 -> ()
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ (Sink# a -> a -> ()) %1 -> Sink# a %1 -> a %1 -> ()
forall a b c (p :: Multiplicity) (q :: Multiplicity)
       (x :: Multiplicity) (y :: Multiplicity).
(a %p -> b %q -> c) %1 -> a %x -> b %y -> c
Unsafe.toLinear2 \(Sink# MVar# RealWorld a
mv) !a
a ->
  (State# RealWorld -> ()) -> ()
forall o. (State# RealWorld -> o) -> o
GHC.runRW# \State# RealWorld
s ->
    case MVar# RealWorld a -> a -> State# RealWorld -> State# RealWorld
forall d a. MVar# d a -> a -> State# d -> State# d
GHC.putMVar# MVar# RealWorld a
mv a
a State# RealWorld
s of
      !State# RealWorld
_ -> ()

instance LinearOnly (Sink# a) where
  linearOnly :: LinearOnlyWitness (Sink# a)
linearOnly = LinearOnlyWitness (Sink# a)
forall {k} (a :: k). LinearOnlyWitness a
UnsafeLinearOnly

instance LinearOnly (Source# a) where
  linearOnly :: LinearOnlyWitness (Source# a)
linearOnly = LinearOnlyWitness (Source# a)
forall {k} (a :: k). LinearOnlyWitness a
UnsafeLinearOnly