{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UnliftedNewtypes #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# OPTIONS_HADDOCK hide #-}

module Control.Monad.Borrow.Pure.Affine.Internal (
  module Control.Monad.Borrow.Pure.Affine.Internal,
) where

import Data.Comonad.Linear qualified as Data
import Data.Functor.Linear qualified as Data
import Data.Int
import Data.Kind
import Data.Monoid qualified as Mon
import Data.Semigroup qualified as Sem
import Data.Unrestricted.Linear
import Data.Word
import GHC.Base
import Generics.Linear
import Prelude.Linear qualified as PL
import Unsafe.Linear qualified as Unsafe

data Aff a where
  UnsafeAff :: !a %One -> Aff a

unaff :: Aff a %1 -> a
unaff :: forall a. Aff a %1 -> a
unaff (UnsafeAff !a
a) = a
a
{-# INLINE unaff #-}

{- | You can bring unrestricted resources into 'Aff' context.

Note that, when you use 'aff' to bring a foreign resource (e.g. 'Foreign.Ptr'),
it is user's responsibility to ensure 'Forign.free' is called on the resource after the @'Aff' ('Foreign.Ptr' a)@ is popped.
-}
affu :: a -> Aff a
affu :: forall a. a -> Aff a
affu = a -> Aff a
forall a. a -> Aff a
UnsafeAff
{-# INLINE affu #-}

pop :: Aff a %1 -> ()
pop :: forall a. Aff a %1 -> ()
pop = (Aff a -> ()) %1 -> Aff a %1 -> ()
forall a b (p :: Multiplicity) (x :: Multiplicity).
(a %p -> b) %1 -> a %x -> b
Unsafe.toLinear (\(UnsafeAff a
_) -> ())
{-# INLINE pop #-}

instance Consumable (Aff a) where
  consume :: Aff a %1 -> ()
consume = Aff a %1 -> ()
forall a. Aff a %1 -> ()
pop
  {-# INLINE consume #-}

instance Data.Functor Aff where
  fmap :: forall a b. (a %1 -> b) -> Aff a %1 -> Aff b
fmap a %1 -> b
f (UnsafeAff a
a) = b -> Aff b
forall a. a -> Aff a
UnsafeAff (a %1 -> b
f a
a)
  {-# INLINE fmap #-}

instance Data.Comonad Aff where
  extract :: forall a. Aff a %1 -> a
extract (UnsafeAff a
a) = a
a
  {-# INLINE extract #-}

  duplicate :: forall a. Aff a %1 -> Aff (Aff a)
duplicate (UnsafeAff a
a) = Aff a -> Aff (Aff a)
forall a. a -> Aff a
UnsafeAff (a -> Aff a
forall a. a -> Aff a
UnsafeAff a
a)
  {-# INLINE duplicate #-}

instance Data.ComonadApply Aff where
  (UnsafeAff a %1 -> b
f) <@> :: forall a b. Aff (a %1 -> b) %1 -> Aff a %1 -> Aff b
<@> (UnsafeAff a
a) = b -> Aff b
forall a. a -> Aff a
UnsafeAff (a %1 -> b
f a
a)
  {-# INLINE (<@>) #-}

type Affine :: Type -> Constraint
class Affine a where
  aff :: a %1 -> Aff a

instance (Movable a) => Affine (AsMovable a) where
  aff :: AsMovable a %1 -> Aff (AsMovable a)
aff (AsMovable a
a) = a %1 -> Ur a
forall a. Movable a => a %1 -> Ur a
move a
a Ur a %1 -> (Ur a %1 -> Aff (AsMovable a)) -> Aff (AsMovable a)
forall a b (p :: Multiplicity) (q :: Multiplicity).
a %p -> (a %p -> b) %q -> b
PL.& \(Ur a
x) -> AsMovable a -> Aff (AsMovable a)
forall a. a -> Aff a
UnsafeAff (a -> AsMovable a
forall a. a -> AsMovable a
AsMovable a
x)
  {-# INLINE aff #-}

deriving via AsMovable (Ur a) instance Affine (Ur a)

deriving via AsMovable Bool instance Affine Bool

deriving via AsMovable Char instance Affine Char

deriving via AsMovable Int instance Affine Int

deriving via AsMovable Int8 instance Affine Int8

deriving via AsMovable Int16 instance Affine Int16

deriving via AsMovable Int32 instance Affine Int32

deriving via AsMovable Int64 instance Affine Int64

deriving via AsMovable Word instance Affine Word

deriving via AsMovable Word8 instance Affine Word8

deriving via AsMovable Word16 instance Affine Word16

deriving via AsMovable Word32 instance Affine Word32

deriving via AsMovable Word64 instance Affine Word64

newtype AsAffine a = AsAffine a

instance (Affine a) => Consumable (AsAffine a) where
  consume :: AsAffine a %1 -> ()
consume (AsAffine a
a) = Aff a %1 -> ()
forall a. Aff a %1 -> ()
pop (a %1 -> Aff a
forall a. Affine a => a %1 -> Aff a
aff a
a)
  {-# INLINE consume #-}

deriving newtype instance Affine Sem.Any

deriving newtype instance Affine Sem.All

deriving via GenericallyAffine (Maybe a) instance (Affine a) => Affine (Maybe a)

deriving via
  GenericallyAffine (Either a b)
  instance
    (Affine a, Affine b) => Affine (Either a b)

deriving via GenericallyAffine () instance Affine ()

deriving via
  GenericallyAffine (a, b)
  instance
    (Affine a, Affine b) => Affine (a, b)

deriving via
  GenericallyAffine (a, b, c)
  instance
    (Affine a, Affine b, Affine c) => Affine (a, b, c)

deriving via
  GenericallyAffine (a, b, c, d)
  instance
    (Affine a, Affine b, Affine c, Affine d) => Affine (a, b, c, d)

deriving via
  GenericallyAffine (a, b, c, d, e)
  instance
    (Affine a, Affine b, Affine c, Affine d, Affine e) => Affine (a, b, c, d, e)

deriving via GenericallyAffine (Sem.Sum a) instance (Affine a) => Affine (Sem.Sum a)

deriving via GenericallyAffine (Sem.Product a) instance (Affine a) => Affine (Sem.Product a)

deriving via GenericallyAffine (Sem.First a) instance (Affine a) => Affine (Sem.First a)

deriving via GenericallyAffine (Sem.Last a) instance (Affine a) => Affine (Sem.Last a)

deriving via GenericallyAffine (Sem.Dual a) instance (Affine a) => Affine (Sem.Dual a)

deriving via GenericallyAffine [a] instance (Affine a) => Affine [a]

deriving via (Maybe a) instance (Affine a) => Affine (Mon.First a)

deriving via (Maybe a) instance (Affine a) => Affine (Mon.Last a)

-- * Generics

{- | We need this instead of 'Generically' becuase
it gives a different 'Consumable' instance.
-}
newtype GenericallyAffine a = GenericallyAffine a

unGenericallyAffine :: GenericallyAffine a %1 -> a
unGenericallyAffine :: forall a. GenericallyAffine a %1 -> a
unGenericallyAffine (GenericallyAffine a
a) = a
a

deriving via
  AsAffine (GenericallyAffine a)
  instance
    (GenericAffine a) => Consumable (GenericallyAffine a)

instance (GenericAffine a) => Affine (GenericallyAffine a) where
  aff :: GenericallyAffine a %1 -> Aff (GenericallyAffine a)
aff = (a %1 -> GenericallyAffine a)
-> Aff a %1 -> Aff (GenericallyAffine a)
forall a b. (a %1 -> b) -> Aff a %1 -> Aff b
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.fmap a -> GenericallyAffine a
forall a. a -> GenericallyAffine a
GenericallyAffine (Aff a %1 -> Aff (GenericallyAffine a))
-> (GenericallyAffine a %1 -> Aff a)
-> GenericallyAffine a
%1 -> Aff (GenericallyAffine a)
forall b c a (q :: Multiplicity) (m :: Multiplicity)
       (n :: Multiplicity).
(b %1 -> c) %q -> (a %1 -> b) %m -> a %n -> c
PL.. a %1 -> Aff a
forall a. GenericAffine a => a %1 -> Aff a
genericAff (a %1 -> Aff a)
-> (GenericallyAffine a %1 -> a) -> GenericallyAffine a %1 -> Aff a
forall b c a (q :: Multiplicity) (m :: Multiplicity)
       (n :: Multiplicity).
(b %1 -> c) %q -> (a %1 -> b) %m -> a %n -> c
PL.. GenericallyAffine a %1 -> a
forall a. GenericallyAffine a %1 -> a
unGenericallyAffine
  {-# INLINE aff #-}

genericAff :: (GenericAffine a) => a %1 -> Aff a
genericAff :: forall a. GenericAffine a => a %1 -> Aff a
genericAff a
a = Rep a (ZonkAny 0) %1 -> a
forall a p (m :: Multiplicity). Generic a => Rep a p %m -> a
forall p (m :: Multiplicity). Rep a p %m -> a
to (Rep a (ZonkAny 0) %1 -> a) -> Aff (Rep a (ZonkAny 0)) %1 -> Aff a
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> Rep a (ZonkAny 0) %1 -> Aff (Rep a (ZonkAny 0))
forall a. Rep a a %1 -> Aff (Rep a a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff (a %1 -> Rep a (ZonkAny 0)
forall a p (m :: Multiplicity). Generic a => a %m -> Rep a p
forall p (m :: Multiplicity). a %m -> Rep a p
from a
a)

{- | A constraint synonym for types for which 'Affine' instance
can be safely derived via 'Generically'.
-}
class (Generic a, GAffine (Rep a)) => GenericAffine a

instance (Generic a, GAffine (Rep a)) => GenericAffine a

type GAffine :: (k -> Type) -> Constraint
class GAffine f where
  gaff :: f a %1 -> Aff (f a)

instance (Affine a) => GAffine (K1 i a) where
  gaff :: forall (a :: k). K1 i a a %1 -> Aff (K1 i a a)
gaff (K1 a
a) = a -> K1 i a a
forall k i c (p :: k). c -> K1 i c p
K1 (a %1 -> K1 i a a) -> Aff a %1 -> Aff (K1 i a a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> a %1 -> Aff a
forall a. Affine a => a %1 -> Aff a
aff a
a
  {-# INLINE gaff #-}

instance (GAffine f, GAffine g) => GAffine (f :+: g) where
  gaff :: forall (a :: k). (:+:) f g a %1 -> Aff ((:+:) f g a)
gaff (L1 f a
x) = f a -> (:+:) f g a
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1 (f a %1 -> (:+:) f g a) -> Aff (f a) %1 -> Aff ((:+:) f g a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> f a %1 -> Aff (f a)
forall (a :: k). f a %1 -> Aff (f a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff f a
x
  gaff (R1 g a
y) = g a -> (:+:) f g a
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 (g a %1 -> (:+:) f g a) -> Aff (g a) %1 -> Aff ((:+:) f g a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> g a %1 -> Aff (g a)
forall (a :: k). g a %1 -> Aff (g a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff g a
y
  {-# INLINE gaff #-}

instance (GAffine f, GAffine g) => GAffine (f :*: g) where
  gaff :: forall (a :: k). (:*:) f g a %1 -> Aff ((:*:) f g a)
gaff (f a
x :*: g a
y) = f a -> g a -> (:*:) f g a
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
(:*:) (f a %1 -> g a %1 -> (:*:) f g a)
-> Aff (f a) %1 -> Aff (g a %1 -> (:*:) f g a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> f a %1 -> Aff (f a)
forall (a :: k). f a %1 -> Aff (f a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff f a
x Aff (g a %1 -> (:*:) f g a) %1 -> Aff (g a) %1 -> Aff ((:*:) f g a)
forall a b. Aff (a %1 -> b) %1 -> Aff a %1 -> Aff b
forall (w :: * -> *) a b.
ComonadApply w =>
w (a %1 -> b) %1 -> w a %1 -> w b
Data.<@> g a %1 -> Aff (g a)
forall (a :: k). g a %1 -> Aff (g a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff g a
y
  {-# INLINE gaff #-}

instance GAffine (MP1 Many f) where
  gaff :: forall (a :: k). MP1 'Many f a %1 -> Aff (MP1 'Many f a)
gaff (MP1 f a
x) = MP1 'Many f a -> Aff (MP1 'Many f a)
forall a. a -> Aff a
UnsafeAff (f a -> MP1 'Many f a
forall {k} (b :: k -> *) (c :: k) (a :: Multiplicity).
b c %a -> MP1 a b c
MP1 f a
x)
  {-# INLINE gaff #-}

instance (GAffine f) => GAffine (MP1 One f) where
  gaff :: forall (a :: k). MP1 'One f a %1 -> Aff (MP1 'One f a)
gaff (MP1 f a
x) = f a %1 -> MP1 'One f a
forall {k} (b :: k -> *) (c :: k) (a :: Multiplicity).
b c %a -> MP1 a b c
MP1 (f a %1 -> MP1 'One f a) -> Aff (f a) %1 -> Aff (MP1 'One f a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> f a %1 -> Aff (f a)
forall (a :: k). f a %1 -> Aff (f a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff f a
x
  {-# INLINE gaff #-}

instance GAffine V1 where
  gaff :: forall (a :: k). V1 a %1 -> Aff (V1 a)
gaff = \case {}
  {-# INLINE gaff #-}

instance GAffine U1 where
  gaff :: forall (a :: k). U1 a %1 -> Aff (U1 a)
gaff U1 a
U1 = U1 a -> Aff (U1 a)
forall a. a -> Aff a
UnsafeAff U1 a
forall k (p :: k). U1 p
U1
  {-# INLINE gaff #-}

instance (GAffine f) => GAffine (M1 i c f) where
  gaff :: forall (a :: k). M1 i c f a %1 -> Aff (M1 i c f a)
gaff (M1 f a
x) = f a -> M1 i c f a
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 (f a %1 -> M1 i c f a) -> Aff (f a) %1 -> Aff (M1 i c f a)
forall (f :: * -> *) a b. Functor f => (a %1 -> b) -> f a %1 -> f b
Data.<$> f a %1 -> Aff (f a)
forall (a :: k). f a %1 -> Aff (f a)
forall k (f :: k -> *) (a :: k). GAffine f => f a %1 -> Aff (f a)
gaff f a
x
  {-# INLINE gaff #-}