{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_HADDOCK hide #-}
module Capability.Sink.Internal.Strategies
( SinkStack(..)
, SinkDList(..)
, SinkLog(..)
) where
import Capability.Accessors
import Capability.Source.Internal.Class
import Capability.Sink.Internal.Class
import Capability.State.Internal.Class
import Capability.State.Internal.Strategies.Common
import Control.Lens (set)
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Primitive (PrimMonad)
import qualified Control.Monad.State.Class as State
import Control.Monad.Trans.Class (MonadTrans, lift)
import Data.Coerce (Coercible, coerce)
import Data.DList (DList)
import qualified Data.DList as DList
import qualified Data.Generics.Product.Fields as Generic
import qualified Data.Generics.Product.Positions as Generic
import Data.IORef
import Data.Mutable
import Streaming
import qualified Streaming.Prelude as S
newtype SinkStack m (a :: *) = SinkStack (m a)
deriving (Functor, Applicative, Monad, MonadIO, PrimMonad)
instance HasState tag [a] m => HasSink tag a (SinkStack m) where
yield_ _ a = coerce @(m ()) $ modify' @tag (a:)
{-# INLINE yield_ #-}
newtype SinkDList m (a :: *) = SinkDList (m a)
deriving (Functor, Applicative, Monad, MonadIO, PrimMonad)
instance HasSink tag (DList a) m => HasSink tag a (SinkDList m) where
yield_ _ = coerce @(a -> m ()) $ yield @tag . DList.singleton
{-# INLINE yield_ #-}
newtype SinkLog m (a :: *) = SinkLog (m a)
deriving (Functor, Applicative, Monad, MonadIO, PrimMonad)
instance (Monoid w, HasState tag w m) => HasSink tag w (SinkLog m) where
yield_ _ w = coerce @(m ()) $ modify' @tag (<> w)
{-# INLINE yield_ #-}
instance Monad m => HasSink tag a (S.Stream (Of a) m) where
yield_ _ = S.yield
{-# INLINE yield_ #-}
instance (HasSink tag a m, MonadTrans t, Monad (t m))
=> HasSink tag a (Lift (t m))
where
yield_ _ = coerce @(a -> t m ()) $ lift . yield @tag
{-# INLINE yield_ #-}
deriving via ((t2 :: (* -> *) -> * -> *) ((t1 :: (* -> *) -> * -> *) m))
instance
( forall x. Coercible (m x) (t2 (t1 m) x)
, Monad m, HasSink tag a (t2 (t1 m)) )
=> HasSink tag a ((t2 :.: t1) m)
instance
( Coercible from to, HasSink tag from m )
=> HasSink tag to (Coerce to m)
where
yield_ tag = coerce @(from -> m ()) $ yield_ tag
{-# INLINE yield_ #-}
instance HasSink oldtag s m => HasSink newtag s (Rename oldtag m) where
yield_ _ = coerce @(s -> m ()) $ yield @oldtag
{-# INLINE yield_ #-}
instance
( tag ~ field, Generic.HasField' field record v, HasState oldtag record m )
=> HasSink tag v (Field field oldtag m)
where
yield_ _ = coerce @(v -> m ()) $
modify @oldtag . set (Generic.field' @field @record)
{-# INLINE yield_ #-}
instance
( tag ~ pos, Generic.HasPosition' pos struct v, HasState oldtag struct m )
=> HasSink tag v (Pos pos oldtag m)
where
yield_ _ = coerce @(v -> m ()) $
modify @oldtag . set (Generic.position' @pos @struct)
{-# INLINE yield_ #-}
instance State.MonadState s m => HasSink tag s (MonadState m) where
yield_ _ = coerce @(s -> m ()) State.put
{-# INLINE yield_ #-}
instance
(HasSource tag (IORef s) m, MonadIO m)
=> HasSink tag s (ReaderIORef m)
where
yield_ _ v = ReaderIORef $ do
ref <- await @tag
liftIO $ writeIORef ref v
{-# INLINE yield_ #-}
instance
( MutableRef ref, RefElement ref ~ s
, HasSource tag ref m, PrimMonad m, PrimState m ~ MCState ref )
=> HasSink tag s (ReaderRef m)
where
yield_ _ v = ReaderRef $ do
ref <- await @tag
writeRef ref v
{-# INLINE yield_ #-}