module Gamgee.Effects.CryptoRandom
    ( -- * Effect
      CryptoRandom(..)

      -- * Action
    , randomBytes

      -- * Interpretations
    , runCryptoRandomIO
    ) where

import qualified Crypto.Random.Types as CRT
import qualified Data.ByteArray      as BA
import           Polysemy            (Embed, Member, Sem)
import qualified Polysemy            as P
import           Relude


----------------------------------------------------------------------------------------------------
-- Effects
----------------------------------------------------------------------------------------------------

-- | An effect capable of providing random bytes for use with cryptonite
data CryptoRandom m a where
  -- | Generate random bytes
  RandomBytes :: BA.ByteArray b => Int -> CryptoRandom m b

P.makeSem ''CryptoRandom


----------------------------------------------------------------------------------------------------
-- Interpretations
----------------------------------------------------------------------------------------------------

runCryptoRandomIO :: Member (Embed IO) r => Sem (CryptoRandom : r) a -> Sem r a
runCryptoRandomIO :: Sem (CryptoRandom : r) a -> Sem r a
runCryptoRandomIO = (forall x (rInitial :: EffectRow).
 CryptoRandom (Sem rInitial) x -> Sem r x)
-> Sem (CryptoRandom : r) a -> Sem r a
forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall x (rInitial :: EffectRow). e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
P.interpret ((forall x (rInitial :: EffectRow).
  CryptoRandom (Sem rInitial) x -> Sem r x)
 -> Sem (CryptoRandom : r) a -> Sem r a)
-> (forall x (rInitial :: EffectRow).
    CryptoRandom (Sem rInitial) x -> Sem r x)
-> Sem (CryptoRandom : r) a
-> Sem r a
forall a b. (a -> b) -> a -> b
$ \case
  RandomBytes count -> forall (r :: EffectRow) a. Member (Embed IO) r => IO a -> Sem r a
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
P.embed @IO (IO x -> Sem r x) -> IO x -> Sem r x
forall a b. (a -> b) -> a -> b
$ Int -> IO x
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
CRT.getRandomBytes Int
count