{-# LANGUAGE DeriveAnyClass  #-}
{-# LANGUAGE StrictData      #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies    #-}
{-# LANGUAGE TypeOperators   #-}

module PlutusCore.Evaluation.Machine.MachineParameters
where

import PlutusCore.Builtin

import PlutusCore.Evaluation.Machine.ExBudget ()

import Control.DeepSeq
import Control.Lens
import GHC.Exts (inline)
import GHC.Generics
import GHC.Types (Type)
import NoThunks.Class

{-| We need to account for the costs of evaluator steps and also built-in function
   evaluation.  The models for these have different structures and are used in
   different parts of the code, so inside the valuator we pass separate objects
   about most of the time .  It's convenient for clients of the evaluator to
   only have to worry about a single object, so the CostModel type bundles the
   two together.  We could conceivably have different evaluators with different
   internal costs, so we keep the machine costs abstract.  The model for Cek
   machine steps is in UntypedPlutusCore.Evaluation.Machine.Cek.CekMachineCosts.
-}
data CostModel machinecosts builtincosts =
    CostModel {
      CostModel machinecosts builtincosts -> machinecosts
_machineCostModel :: machinecosts
    , CostModel machinecosts builtincosts -> builtincosts
_builtinCostModel :: builtincosts
    } deriving stock (CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
(CostModel machinecosts builtincosts
 -> CostModel machinecosts builtincosts -> Bool)
-> (CostModel machinecosts builtincosts
    -> CostModel machinecosts builtincosts -> Bool)
-> Eq (CostModel machinecosts builtincosts)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall machinecosts builtincosts.
(Eq machinecosts, Eq builtincosts) =>
CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
/= :: CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
$c/= :: forall machinecosts builtincosts.
(Eq machinecosts, Eq builtincosts) =>
CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
== :: CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
$c== :: forall machinecosts builtincosts.
(Eq machinecosts, Eq builtincosts) =>
CostModel machinecosts builtincosts
-> CostModel machinecosts builtincosts -> Bool
Eq, Int -> CostModel machinecosts builtincosts -> ShowS
[CostModel machinecosts builtincosts] -> ShowS
CostModel machinecosts builtincosts -> String
(Int -> CostModel machinecosts builtincosts -> ShowS)
-> (CostModel machinecosts builtincosts -> String)
-> ([CostModel machinecosts builtincosts] -> ShowS)
-> Show (CostModel machinecosts builtincosts)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
Int -> CostModel machinecosts builtincosts -> ShowS
forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
[CostModel machinecosts builtincosts] -> ShowS
forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
CostModel machinecosts builtincosts -> String
showList :: [CostModel machinecosts builtincosts] -> ShowS
$cshowList :: forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
[CostModel machinecosts builtincosts] -> ShowS
show :: CostModel machinecosts builtincosts -> String
$cshow :: forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
CostModel machinecosts builtincosts -> String
showsPrec :: Int -> CostModel machinecosts builtincosts -> ShowS
$cshowsPrec :: forall machinecosts builtincosts.
(Show machinecosts, Show builtincosts) =>
Int -> CostModel machinecosts builtincosts -> ShowS
Show)
makeLenses ''CostModel

{-| At execution time we need a 'BuiltinsRuntime' object which includes both the
  cost model for builtins and their denotations.  This bundles one of those
  together with the cost model for evaluator steps.  The 'term' type will be
  CekValue when we're using this with the CEK machine. -}
data MachineParameters machinecosts term (uni :: Type -> Type) (fun :: Type) =
    MachineParameters {
      MachineParameters machinecosts term uni fun -> machinecosts
machineCosts    :: machinecosts
    , MachineParameters machinecosts term uni fun
-> BuiltinsRuntime fun (term uni fun)
builtinsRuntime :: BuiltinsRuntime fun (term uni fun)
    }
    deriving stock (forall x.
 MachineParameters machinecosts term uni fun
 -> Rep (MachineParameters machinecosts term uni fun) x)
-> (forall x.
    Rep (MachineParameters machinecosts term uni fun) x
    -> MachineParameters machinecosts term uni fun)
-> Generic (MachineParameters machinecosts term uni fun)
forall x.
Rep (MachineParameters machinecosts term uni fun) x
-> MachineParameters machinecosts term uni fun
forall x.
MachineParameters machinecosts term uni fun
-> Rep (MachineParameters machinecosts term uni fun) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun x.
Rep (MachineParameters machinecosts term uni fun) x
-> MachineParameters machinecosts term uni fun
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun x.
MachineParameters machinecosts term uni fun
-> Rep (MachineParameters machinecosts term uni fun) x
$cto :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun x.
Rep (MachineParameters machinecosts term uni fun) x
-> MachineParameters machinecosts term uni fun
$cfrom :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun x.
MachineParameters machinecosts term uni fun
-> Rep (MachineParameters machinecosts term uni fun) x
Generic
    deriving anyclass (MachineParameters machinecosts term uni fun -> ()
(MachineParameters machinecosts term uni fun -> ())
-> NFData (MachineParameters machinecosts term uni fun)
forall a. (a -> ()) -> NFData a
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
(NFData machinecosts, NFData fun) =>
MachineParameters machinecosts term uni fun -> ()
rnf :: MachineParameters machinecosts term uni fun -> ()
$crnf :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
(NFData machinecosts, NFData fun) =>
MachineParameters machinecosts term uni fun -> ()
NFData, Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
Proxy (MachineParameters machinecosts term uni fun) -> String
(Context
 -> MachineParameters machinecosts term uni fun
 -> IO (Maybe ThunkInfo))
-> (Context
    -> MachineParameters machinecosts term uni fun
    -> IO (Maybe ThunkInfo))
-> (Proxy (MachineParameters machinecosts term uni fun) -> String)
-> NoThunks (MachineParameters machinecosts term uni fun)
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
NoThunks machinecosts =>
Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
NoThunks machinecosts =>
Proxy (MachineParameters machinecosts term uni fun) -> String
showTypeOf :: Proxy (MachineParameters machinecosts term uni fun) -> String
$cshowTypeOf :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
NoThunks machinecosts =>
Proxy (MachineParameters machinecosts term uni fun) -> String
wNoThunks :: Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
$cwNoThunks :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
NoThunks machinecosts =>
Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
noThunks :: Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
$cnoThunks :: forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
NoThunks machinecosts =>
Context
-> MachineParameters machinecosts term uni fun
-> IO (Maybe ThunkInfo)
NoThunks)

-- See Note [Inlining meanings of builtins].
{-| This just uses 'toBuiltinsRuntime' function to convert a BuiltinCostModel to a BuiltinsRuntime. -}
mkMachineParameters ::
    ( -- In Cek.Internal we have `type instance UniOf (CekValue uni fun) = uni`, but we don't know that here.
      CostingPart uni fun ~ builtincosts
    , HasConstantIn uni (val uni fun)
    , ToBuiltinMeaning uni fun
    )
    => UnliftingMode
    -> CostModel machinecosts builtincosts
    -> MachineParameters machinecosts val uni fun
mkMachineParameters :: UnliftingMode
-> CostModel machinecosts builtincosts
-> MachineParameters machinecosts val uni fun
mkMachineParameters UnliftingMode
unlMode (CostModel machinecosts
mchnCosts builtincosts
builtinCosts) =
    machinecosts
-> BuiltinsRuntime fun (val uni fun)
-> MachineParameters machinecosts val uni fun
forall machinecosts (term :: (* -> *) -> * -> *) (uni :: * -> *)
       fun.
machinecosts
-> BuiltinsRuntime fun (term uni fun)
-> MachineParameters machinecosts term uni fun
MachineParameters machinecosts
mchnCosts ((UnliftingMode
 -> builtincosts -> BuiltinsRuntime fun (val uni fun))
-> UnliftingMode
-> builtincosts
-> BuiltinsRuntime fun (val uni fun)
forall a. a -> a
inline UnliftingMode -> builtincosts -> BuiltinsRuntime fun (val uni fun)
forall cost (uni :: * -> *) fun val.
(cost ~ CostingPart uni fun, HasConstantIn uni val,
 ToBuiltinMeaning uni fun) =>
UnliftingMode -> cost -> BuiltinsRuntime fun val
toBuiltinsRuntime UnliftingMode
unlMode builtincosts
builtinCosts)
{-# INLINE mkMachineParameters #-}