-- | Object capability based IO.
--
-- See <https://github.com/zenhack/haskell-ocap/blob/master/README.md> for
-- an overview.
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE Safe          #-}
module OCap.IO
    ( OCapIO
    , IOKey
    , getIOKey
    , runOCap
    , runIO
    ) where

import OCap.IO.Internal

-- | The 'OCapIO' monad is like 'IO', except that it does not provide "ambient"
-- authoirty -- in order to perform IO, you also need an 'IOKey'.
newtype OCapIO a = OCapIO (IO a) deriving (Functor)

-- These instances are exactly what you would get with GeneralizedNewtypeDeriving,
-- but we can't use that because it is incompatible with Safe, so we have to write
-- some boilerplate.
instance Applicative OCapIO where
    pure = OCapIO . pure
    OCapIO f <*> OCapIO x = OCapIO (f <*> x)
instance Monad OCapIO where
    return = pure
    OCapIO x >>= f = OCapIO $ do
        x' <- x
        let OCapIO fx = f x'
        fx
instance Semigroup a => Semigroup (OCapIO a) where
    OCapIO x <> OCapIO y = OCapIO (x <> y)
instance Monoid a => Monoid (OCapIO a) where
    mempty = OCapIO mempty

-- | Gets an 'IOKey', which can later be used to perform 'IO' actions inside
-- the 'OCapIO' monad.
getIOKey :: IO IOKey
getIOKey = pure IOKey

-- | Run an 'OCapIO' action.
runOCap :: OCapIO a -> IO a
runOCap (OCapIO io) = io

-- | Run an 'IO' action inside of 'CapIO'.
runIO :: IO a -> IOKey -> OCapIO a
-- Note: it is CRITICAL that we force evaluation of the IOKey here;
-- otherwise someone could just pass undefined and circumvent the entirety
-- of the protection provided by OCapIO.
runIO io IOKey = OCapIO io