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

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

import Control.Concurrent.DivideConquer.Utils.OnceChan.Linear.Unlifted
import Control.Monad.Borrow.Pure.Affine
import Control.Monad.Borrow.Pure.Affine.Unsafe (unsafeAff)
import Control.Monad.Borrow.Pure.BO
import Control.Monad.Borrow.Pure.Lifetime.Token.Unsafe (
  LinearOnly (..),
  LinearOnlyWitness (..),
 )
import Data.Unrestricted.Linear
import Prelude.Linear hiding (take)
import Unsafe.Linear qualified as Unsafe

data Sink a = Sink (Sink# a)

data Source a = Source (Source# a)

type role Sink nominal

type role Source representational

new :: Linearly %1 -> (Sink a, Source a)
{-# INLINE new #-}
new :: forall a. Linearly %1 -> (Sink a, Source a)
new Linearly
lin = case Linearly %1 -> (# Sink# a, Source# a #)
forall a. Linearly %1 -> (# Sink# a, Source# a #)
new# Linearly
lin of
  (# Sink# a
sink, Source# a
source #) -> (Sink# a -> Sink a
forall a. Sink# a -> Sink a
Sink Sink# a
sink, Source# a -> Source a
forall a. Source# a -> Source a
Source Source# a
source)

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

instance Affine (Sink a) where
  aff :: Sink a %1 -> Aff (Sink a)
aff = Sink a %1 -> Aff (Sink a)
forall a. a %1 -> Aff a
unsafeAff

instance Consumable (Sink a) where
  consume :: Sink a %1 -> ()
consume = (Sink a -> ()) %1 -> Sink a %1 -> ()
forall a b (p :: Multiplicity) (x :: Multiplicity).
(a %p -> b) %1 -> a %x -> b
Unsafe.toLinear \(Sink !Sink# a
_) -> ()

instance Consumable (Source a) where
  consume :: Source a %1 -> ()
consume = (Source a -> ()) %1 -> Source a %1 -> ()
forall a b (p :: Multiplicity) (x :: Multiplicity).
(a %p -> b) %1 -> a %x -> b
Unsafe.toLinear \(Source !Source# a
_) -> ()

instance Affine (Source a) where
  aff :: Source a %1 -> Aff (Source a)
aff = Source a %1 -> Aff (Source a)
forall a. a %1 -> Aff a
unsafeAff

take :: Source a %1 -> BO α a
{-# INLINE take #-}
take :: forall a (α :: Lifetime). Source a %1 -> BO α a
take (Source Source# a
v) = a %1 -> BO α a
forall a (α :: Lifetime). a %1 -> BO α a
evaluateBO (a %1 -> BO α a) -> a %1 -> BO α a
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ Source# a %1 -> a
forall a. Source# a %1 -> a
take# Source# a
v

put :: Sink a %1 -> a %1 -> BO α ()
{-# INLINE put #-}
put :: forall a (α :: Lifetime). Sink a %1 -> a %1 -> BO α ()
put (Sink Sink# a
v) !a
a = () %1 -> BO α ()
forall a (α :: Lifetime). a %1 -> BO α a
evaluateBO (() %1 -> BO α ()) -> () %1 -> BO α ()
forall a b (p :: Multiplicity) (q :: Multiplicity).
(a %p -> b) %q -> a %p -> b
$ Sink# a %1 -> a %1 -> ()
forall a. Sink# a %1 -> a %1 -> ()
put# Sink# a
v a
a