{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-}
module PlutusTx.Blueprint.Definition.Unroll where
import Prelude
import Data.Kind (Type)
import Data.Text (Text)
import GHC.Generics (Generic (Rep), K1, M1, U1, type (:*:), type (:+:))
import GHC.TypeLits qualified as GHC
import PlutusTx.Blueprint.Class (HasSchema)
import PlutusTx.Blueprint.Definition.Id as DefinitionId (AsDefinitionId (..))
import PlutusTx.Blueprint.Definition.Internal (Definitions (..), addDefinition, definition)
import PlutusTx.Builtins.Internal (BuiltinByteString, BuiltinData, BuiltinList, BuiltinPair,
BuiltinString, BuiltinUnit)
type family UnrollAll xs :: [Type] where
UnrollAll '[] = '[]
UnrollAll (x ': xs) = Concat (Unroll x) (UnrollAll xs)
type family Unroll (p :: Type) :: [Type] where
Unroll Int = '[Int]
Unroll Integer = '[Integer]
Unroll Text = '[Text]
Unroll BuiltinData = '[BuiltinData]
Unroll BuiltinUnit = '[BuiltinUnit]
Unroll BuiltinString = '[BuiltinString]
Unroll (BuiltinList a) = Unroll a
Unroll (BuiltinPair a b) = Unroll a ++ Unroll b
Unroll BuiltinByteString = '[BuiltinByteString]
Unroll [a] = Unroll a
Unroll (a, b) = Unroll a ++ Unroll b
Unroll (Maybe a) = Unroll a
Unroll p = Prepend p (GUnroll (Break (NoGeneric p) (Rep p)))
type family Break e (rep :: Type -> Type) :: Type -> Type where
Break _ (M1 a b c) = M1 a b c
Break _ (f :*: g) = f :*: g
Break _ (f :+: g) = f :+: g
Break _ (K1 a b) = K1 a b
Break e U1 = U1
Break e x = e
type family NoGeneric t where
NoGeneric x = GHC.TypeError (GHC.Text "No instance for " GHC.:<>: GHC.ShowType (Generic x))
type family GUnroll (t :: Type -> Type) :: [Type] where
GUnroll (M1 _ _ f) = GUnroll f
GUnroll (f :*: g) = GUnroll f ++ GUnroll g
GUnroll (f :+: g) = GUnroll f ++ GUnroll g
GUnroll (K1 _ c) = Unroll c
GUnroll U1 = '[]
type Insert :: forall k. k -> [k] -> [k]
type family Insert x xs where
Insert x '[] = '[x]
Insert x (x : xs) = x ': xs
Insert x (y : xs) = y ': Insert x xs
type Prepend :: forall k. k -> [k] -> [k]
type family Prepend x xs where
Prepend x '[] = '[x]
Prepend x (x : xs) = x ': xs
Prepend x (y : xs) = x ': y ': xs
type Concat :: forall k. [k] -> [k] -> [k]
type family Concat (as :: [k]) (bs :: [k]) :: [k] where
Concat '[] bs = bs
Concat as '[] = as
Concat (a : as) bs = a ': Concat as bs
type (++) :: forall k. [k] -> [k] -> [k]
type family (as :: [k]) ++ (bs :: [k]) :: [k] where
'[] ++ bs = bs
as ++ '[] = as
(a : as) ++ bs = Insert a (as ++ bs)
infixr 5 ++
class Unrollable ts where
unroll :: Definitions ts
instance Unrollable '[] where
unroll :: Definitions '[]
unroll = Definitions '[]
NoDefinitions
instance (Unrollable ts, AsDefinitionId t, HasSchema t ts) => Unrollable (t : ts) where
unroll :: Definitions (t : ts)
unroll = Definitions ts -> Definition t ts -> Definitions (t : ts)
forall (ts :: [*]) t.
Definitions ts -> Definition t ts -> Definitions (t : ts)
addDefinition (forall (ts :: [*]). Unrollable ts => Definitions ts
unroll @ts) (forall t (ts :: [*]).
(AsDefinitionId t, HasSchema t ts) =>
Definition t ts
definition @t)
deriveDefinitions :: forall ts. (Unrollable (UnrollAll ts)) => Definitions (UnrollAll ts)
deriveDefinitions :: forall (ts :: [*]).
Unrollable (UnrollAll ts) =>
Definitions (UnrollAll ts)
deriveDefinitions = forall (ts :: [*]). Unrollable ts => Definitions ts
unroll @(UnrollAll ts)