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

module PlutusCore.Evaluation.Machine.MachineParameters
where

import PlutusCore.Builtin

import PlutusCore.Core.Type hiding (Type)
import PlutusCore.Evaluation.Machine.ExBudget ()

import GHC.Types (Type)

{-| 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 (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)

{-| 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)
    }

{-| This just uses 'toBuiltinsRuntime' function to convert a BuiltinCostModel to a BuiltinsRuntime. -}
toMachineParameters ::
    ( UniOf (val uni fun) ~ uni
      -- In Cek.Internal we have `type instance UniOf (CekValue uni fun) = uni`, but we don't know that here.
    , CostingPart uni fun ~ builtincosts
    , HasConstant (val uni fun)
    , ToBuiltinMeaning uni fun
    )
    => CostModel machinecosts builtincosts
    -> MachineParameters machinecosts val uni fun
toMachineParameters :: CostModel machinecosts builtincosts
-> MachineParameters machinecosts val uni fun
toMachineParameters (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 (builtincosts -> BuiltinsRuntime fun (val uni fun)
forall cost (uni :: * -> *) fun val.
(cost ~ CostingPart uni fun, HasConstantIn uni val,
 ToBuiltinMeaning uni fun) =>
cost -> BuiltinsRuntime fun val
toBuiltinsRuntime builtincosts
builtinCosts)