-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

-- | Allows specifying entrypoints without declaring 'ParamterHasEntryPoints'
-- instance.
module Lorentz.EntryPoints.Manual
  ( ParameterWrapper (..)
  ) where

import Control.Lens (Wrapped)
import qualified Data.Kind as Kind

import Lorentz.Constraints
import Lorentz.EntryPoints.Core
import Michelson.Typed

-- | Wrap parameter into this to locally assign a way to derive entrypoints for
-- it.
newtype ParameterWrapper (deriv :: Kind.Type) cp = ParameterWrapper { ParameterWrapper deriv cp -> cp
unParameterWraper :: cp }
  deriving stock (forall x.
 ParameterWrapper deriv cp -> Rep (ParameterWrapper deriv cp) x)
-> (forall x.
    Rep (ParameterWrapper deriv cp) x -> ParameterWrapper deriv cp)
-> Generic (ParameterWrapper deriv cp)
forall x.
Rep (ParameterWrapper deriv cp) x -> ParameterWrapper deriv cp
forall x.
ParameterWrapper deriv cp -> Rep (ParameterWrapper deriv cp) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall deriv cp x.
Rep (ParameterWrapper deriv cp) x -> ParameterWrapper deriv cp
forall deriv cp x.
ParameterWrapper deriv cp -> Rep (ParameterWrapper deriv cp) x
$cto :: forall deriv cp x.
Rep (ParameterWrapper deriv cp) x -> ParameterWrapper deriv cp
$cfrom :: forall deriv cp x.
ParameterWrapper deriv cp -> Rep (ParameterWrapper deriv cp) x
Generic
  deriving anyclass WellTypedToT (ParameterWrapper deriv cp)
WellTypedToT (ParameterWrapper deriv cp) =>
(ParameterWrapper deriv cp
 -> Value (ToT (ParameterWrapper deriv cp)))
-> (Value (ToT (ParameterWrapper deriv cp))
    -> ParameterWrapper deriv cp)
-> IsoValue (ParameterWrapper deriv cp)
Value (ToT (ParameterWrapper deriv cp))
-> ParameterWrapper deriv cp
ParameterWrapper deriv cp
-> Value (ToT (ParameterWrapper deriv cp))
forall a.
WellTypedToT a =>
(a -> Value (ToT a)) -> (Value (ToT a) -> a) -> IsoValue a
forall deriv cp.
IsoValue cp =>
WellTypedToT (ParameterWrapper deriv cp)
forall deriv cp.
IsoValue cp =>
Value (ToT (ParameterWrapper deriv cp))
-> ParameterWrapper deriv cp
forall deriv cp.
IsoValue cp =>
ParameterWrapper deriv cp
-> Value (ToT (ParameterWrapper deriv cp))
fromVal :: Value (ToT (ParameterWrapper deriv cp))
-> ParameterWrapper deriv cp
$cfromVal :: forall deriv cp.
IsoValue cp =>
Value (ToT (ParameterWrapper deriv cp))
-> ParameterWrapper deriv cp
toVal :: ParameterWrapper deriv cp
-> Value (ToT (ParameterWrapper deriv cp))
$ctoVal :: forall deriv cp.
IsoValue cp =>
ParameterWrapper deriv cp
-> Value (ToT (ParameterWrapper deriv cp))
$cp1IsoValue :: forall deriv cp.
IsoValue cp =>
WellTypedToT (ParameterWrapper deriv cp)
IsoValue

instance Wrapped (ParameterWrapper deriv cp)

-- Helper for implementing @instance ParameterHasEntryPoints ParameterWrapper@.
data PwDeriv deriv
instance EntryPointsDerivation deriv cp =>
         EntryPointsDerivation (PwDeriv deriv) (ParameterWrapper deriv cp) where
  type EpdAllEntryPoints (PwDeriv deriv) (ParameterWrapper deriv cp) =
    EpdAllEntryPoints deriv cp
  type EpdLookupEntryPoint (PwDeriv deriv) (ParameterWrapper deriv cp) =
    EpdLookupEntryPoint deriv cp
  epdNotes :: Notes (ToT (ParameterWrapper deriv cp))
epdNotes = EntryPointsDerivation deriv cp => Notes (ToT cp)
forall k (deriv :: k) cp.
EntryPointsDerivation deriv cp =>
Notes (ToT cp)
epdNotes @deriv @cp
  epdCall :: Label name
-> EpConstructionRes
     (ToT (ParameterWrapper deriv cp))
     (Eval
        (EpdLookupEntryPoint
           (PwDeriv deriv) (ParameterWrapper deriv cp) name))
epdCall = forall (name :: Symbol).
(EntryPointsDerivation deriv cp, ParameterScope (ToT cp)) =>
Label name
-> EpConstructionRes
     (ToT cp) (Eval (EpdLookupEntryPoint deriv cp name))
forall k (deriv :: k) cp (name :: Symbol).
(EntryPointsDerivation deriv cp, ParameterScope (ToT cp)) =>
Label name
-> EpConstructionRes
     (ToT cp) (Eval (EpdLookupEntryPoint deriv cp name))
epdCall @deriv @cp
  epdDescs :: Rec
  EpCallingDesc
  (EpdAllEntryPoints (PwDeriv deriv) (ParameterWrapper deriv cp))
epdDescs = EntryPointsDerivation deriv cp =>
Rec EpCallingDesc (EpdAllEntryPoints deriv cp)
forall k (deriv :: k) cp.
EntryPointsDerivation deriv cp =>
Rec EpCallingDesc (EpdAllEntryPoints deriv cp)
epdDescs @deriv @cp

instance ( NiceParameter cp
         , EntryPointsDerivation epd cp
         , RequireAllUniqueEntryPoints' epd cp
         ) =>
         ParameterHasEntryPoints (ParameterWrapper epd cp) where
  type ParameterEntryPointsDerivation (ParameterWrapper epd cp) = PwDeriv epd