{-# LANGUAGE FlexibleContexts         #-}
{-# LANGUAGE FlexibleInstances        #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeFamilies             #-}
{-# LANGUAGE TypeOperators            #-}

module PlutusTx.Builtins.HasBuiltin where

import Prelude

import PlutusCore.Crypto.BLS12_381.G1 qualified as BLS12_381.G1 (Element)
import PlutusCore.Crypto.BLS12_381.G2 qualified as BLS12_381.G2 (Element)
import PlutusCore.Crypto.BLS12_381.Pairing qualified as BLS12_381.Pairing (MlResult)
import PlutusCore.Data (Data)
import PlutusCore.Default qualified as PLC
import PlutusCore.Value (Value)
import PlutusTx.Builtins.Internal

import Data.ByteString (ByteString)
import Data.Kind qualified as GHC
import Data.Text (Text)
import Data.Vector.Strict qualified as Strict

{- Note [useToOpaque and useFromOpaque]
It used to be possible to use 'toBuiltin'/'fromBuiltin' within a smart contract, but this is no
longer the case, hence we throw a compilation error suggesting to use 'toOpaque'/'fromOpaque'
instead.
-}

useToOpaque :: a -> a
useToOpaque :: forall a. a -> a
useToOpaque a
x = a
x
{-# OPAQUE useToOpaque #-}

useFromOpaque :: a -> a
useFromOpaque :: forall a. a -> a
useFromOpaque a
x = a
x
{-# OPAQUE useFromOpaque #-}

-- Also see Note [Built-in types and their Haskell counterparts].

{-| A class for converting values of Haskell-defined built-in types to their Plutus Tx
counterparts.
-}
type HasToBuiltin :: GHC.Type -> GHC.Constraint
class (PLC.DefaultUni `PLC.Contains` a) => HasToBuiltin a where
  type ToBuiltin a
  toBuiltin :: a -> ToBuiltin a

-- Also see Note [Built-in types and their Haskell counterparts].

{-| A class for converting values of Plutus Tx built-in types to their Haskell-defined
counterparts.
-}
type HasFromBuiltin :: GHC.Type -> GHC.Constraint
class (HasToBuiltin (FromBuiltin arep)) => HasFromBuiltin arep where
  type FromBuiltin arep
  fromBuiltin :: arep -> FromBuiltin arep

instance HasToBuiltin Integer where
  type ToBuiltin Integer = BuiltinInteger
  toBuiltin :: Integer -> ToBuiltin Integer
toBuiltin = (Integer -> Integer) -> Integer -> Integer
forall a. a -> a
useToOpaque Integer -> Integer
forall a. a -> a
id
instance HasFromBuiltin BuiltinInteger where
  type FromBuiltin BuiltinInteger = Integer
  fromBuiltin :: Integer -> FromBuiltin Integer
fromBuiltin = (Integer -> Integer) -> Integer -> Integer
forall a. a -> a
useFromOpaque Integer -> Integer
forall a. a -> a
id

instance HasToBuiltin ByteString where
  type ToBuiltin ByteString = BuiltinByteString
  toBuiltin :: ByteString -> ToBuiltin ByteString
toBuiltin = (ByteString -> BuiltinByteString)
-> ByteString -> BuiltinByteString
forall a. a -> a
useToOpaque ByteString -> BuiltinByteString
BuiltinByteString
instance HasFromBuiltin BuiltinByteString where
  type FromBuiltin BuiltinByteString = ByteString
  fromBuiltin :: BuiltinByteString -> FromBuiltin BuiltinByteString
fromBuiltin = (BuiltinByteString -> FromBuiltin BuiltinByteString)
-> BuiltinByteString -> FromBuiltin BuiltinByteString
forall a. a -> a
useFromOpaque ((BuiltinByteString -> FromBuiltin BuiltinByteString)
 -> BuiltinByteString -> FromBuiltin BuiltinByteString)
-> (BuiltinByteString -> FromBuiltin BuiltinByteString)
-> BuiltinByteString
-> FromBuiltin BuiltinByteString
forall a b. (a -> b) -> a -> b
$ \(BuiltinByteString ByteString
b) -> ByteString
FromBuiltin BuiltinByteString
b

instance HasToBuiltin Text where
  type ToBuiltin Text = BuiltinString
  toBuiltin :: Text -> ToBuiltin Text
toBuiltin = (Text -> BuiltinString) -> Text -> BuiltinString
forall a. a -> a
useToOpaque Text -> BuiltinString
BuiltinString
instance HasFromBuiltin BuiltinString where
  type FromBuiltin BuiltinString = Text
  fromBuiltin :: BuiltinString -> FromBuiltin BuiltinString
fromBuiltin (BuiltinString Text
t) = Text
FromBuiltin BuiltinString
t

instance HasToBuiltin () where
  type ToBuiltin () = BuiltinUnit
  toBuiltin :: () -> ToBuiltin ()
toBuiltin = (() -> BuiltinUnit) -> () -> BuiltinUnit
forall a. a -> a
useToOpaque () -> BuiltinUnit
BuiltinUnit
instance HasFromBuiltin BuiltinUnit where
  type FromBuiltin BuiltinUnit = ()
  fromBuiltin :: BuiltinUnit -> FromBuiltin BuiltinUnit
fromBuiltin (BuiltinUnit ()
u) = ()
FromBuiltin BuiltinUnit
u

instance HasToBuiltin Bool where
  type ToBuiltin Bool = Bool
  toBuiltin :: Bool -> ToBuiltin Bool
toBuiltin = (Bool -> Bool) -> Bool -> Bool
forall a. a -> a
useToOpaque Bool -> Bool
forall a. a -> a
id
instance HasFromBuiltin Bool where
  type FromBuiltin Bool = Bool
  fromBuiltin :: Bool -> FromBuiltin Bool
fromBuiltin = Bool -> Bool
Bool -> FromBuiltin Bool
forall a. a -> a
id

instance (HasToBuiltin a) => HasToBuiltin [a] where
  type ToBuiltin [a] = BuiltinList (ToBuiltin a)
  toBuiltin :: [a] -> ToBuiltin [a]
toBuiltin = ([ToBuiltin a] -> BuiltinList (ToBuiltin a))
-> [ToBuiltin a] -> BuiltinList (ToBuiltin a)
forall a. a -> a
useToOpaque [ToBuiltin a] -> BuiltinList (ToBuiltin a)
forall a. [a] -> BuiltinList a
BuiltinList ([ToBuiltin a] -> BuiltinList (ToBuiltin a))
-> ([a] -> [ToBuiltin a]) -> [a] -> BuiltinList (ToBuiltin a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> ToBuiltin a) -> [a] -> [ToBuiltin a]
forall a b. (a -> b) -> [a] -> [b]
map a -> ToBuiltin a
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin
instance (HasFromBuiltin a) => HasFromBuiltin (BuiltinList a) where
  type FromBuiltin (BuiltinList a) = [FromBuiltin a]
  fromBuiltin :: BuiltinList a -> FromBuiltin (BuiltinList a)
fromBuiltin (BuiltinList [a]
xs) = (a -> FromBuiltin a) -> [a] -> [FromBuiltin a]
forall a b. (a -> b) -> [a] -> [b]
map a -> FromBuiltin a
forall arep. HasFromBuiltin arep => arep -> FromBuiltin arep
fromBuiltin [a]
xs

instance (HasToBuiltin a) => HasToBuiltin (Strict.Vector a) where
  type ToBuiltin (Strict.Vector a) = BuiltinArray (ToBuiltin a)
  toBuiltin :: Vector a -> ToBuiltin (Vector a)
toBuiltin = (Vector a -> BuiltinArray (ToBuiltin a))
-> Vector a -> BuiltinArray (ToBuiltin a)
forall a. a -> a
useToOpaque (Vector (ToBuiltin a) -> BuiltinArray (ToBuiltin a)
forall a. Vector a -> BuiltinArray a
BuiltinArray (Vector (ToBuiltin a) -> BuiltinArray (ToBuiltin a))
-> (Vector a -> Vector (ToBuiltin a))
-> Vector a
-> BuiltinArray (ToBuiltin a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> ToBuiltin a) -> Vector a -> Vector (ToBuiltin a)
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> ToBuiltin a
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin)
instance (HasFromBuiltin a) => HasFromBuiltin (BuiltinArray a) where
  type FromBuiltin (BuiltinArray a) = Strict.Vector (FromBuiltin a)
  fromBuiltin :: BuiltinArray a -> FromBuiltin (BuiltinArray a)
fromBuiltin (BuiltinArray Vector a
xs) = (a -> FromBuiltin a) -> Vector a -> Vector (FromBuiltin a)
forall a b. (a -> b) -> Vector a -> Vector b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> FromBuiltin a
forall arep. HasFromBuiltin arep => arep -> FromBuiltin arep
fromBuiltin Vector a
xs

instance (HasToBuiltin a, HasToBuiltin b) => HasToBuiltin (a, b) where
  type ToBuiltin (a, b) = BuiltinPair (ToBuiltin a) (ToBuiltin b)
  toBuiltin :: (a, b) -> ToBuiltin (a, b)
toBuiltin (a
x, b
y) = (ToBuiltin a, ToBuiltin b)
-> BuiltinPair (ToBuiltin a) (ToBuiltin b)
forall a b. (a, b) -> BuiltinPair a b
BuiltinPair (a -> ToBuiltin a
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin a
x, b -> ToBuiltin b
forall a. HasToBuiltin a => a -> ToBuiltin a
toBuiltin b
y)
instance (HasFromBuiltin a, HasFromBuiltin b) => HasFromBuiltin (BuiltinPair a b) where
  type FromBuiltin (BuiltinPair a b) = (FromBuiltin a, FromBuiltin b)
  fromBuiltin :: BuiltinPair a b -> FromBuiltin (BuiltinPair a b)
fromBuiltin (BuiltinPair (a
x, b
y)) = (a -> FromBuiltin a
forall arep. HasFromBuiltin arep => arep -> FromBuiltin arep
fromBuiltin a
x, b -> FromBuiltin b
forall arep. HasFromBuiltin arep => arep -> FromBuiltin arep
fromBuiltin b
y)

instance HasToBuiltin Data where
  type ToBuiltin Data = BuiltinData
  toBuiltin :: Data -> ToBuiltin Data
toBuiltin = (Data -> BuiltinData) -> Data -> BuiltinData
forall a. a -> a
useToOpaque Data -> BuiltinData
BuiltinData
instance HasFromBuiltin BuiltinData where
  type FromBuiltin BuiltinData = Data
  fromBuiltin :: BuiltinData -> FromBuiltin BuiltinData
fromBuiltin (BuiltinData Data
t) = Data
FromBuiltin BuiltinData
t

instance HasToBuiltin Value where
  type ToBuiltin Value = BuiltinValue
  toBuiltin :: Value -> ToBuiltin Value
toBuiltin = (Value -> BuiltinValue) -> Value -> BuiltinValue
forall a. a -> a
useToOpaque Value -> BuiltinValue
BuiltinValue
instance HasFromBuiltin BuiltinValue where
  type FromBuiltin BuiltinValue = Value
  fromBuiltin :: BuiltinValue -> FromBuiltin BuiltinValue
fromBuiltin (BuiltinValue Value
t) = Value
FromBuiltin BuiltinValue
t

instance HasToBuiltin BLS12_381.G1.Element where
  type ToBuiltin BLS12_381.G1.Element = BuiltinBLS12_381_G1_Element
  toBuiltin :: Element -> ToBuiltin Element
toBuiltin = (Element -> BuiltinBLS12_381_G1_Element)
-> Element -> BuiltinBLS12_381_G1_Element
forall a. a -> a
useToOpaque Element -> BuiltinBLS12_381_G1_Element
BuiltinBLS12_381_G1_Element
instance HasFromBuiltin BuiltinBLS12_381_G1_Element where
  type FromBuiltin BuiltinBLS12_381_G1_Element = BLS12_381.G1.Element
  fromBuiltin :: BuiltinBLS12_381_G1_Element
-> FromBuiltin BuiltinBLS12_381_G1_Element
fromBuiltin (BuiltinBLS12_381_G1_Element Element
a) = Element
FromBuiltin BuiltinBLS12_381_G1_Element
a

instance HasToBuiltin BLS12_381.G2.Element where
  type ToBuiltin BLS12_381.G2.Element = BuiltinBLS12_381_G2_Element
  toBuiltin :: Element -> ToBuiltin Element
toBuiltin = (Element -> BuiltinBLS12_381_G2_Element)
-> Element -> BuiltinBLS12_381_G2_Element
forall a. a -> a
useToOpaque Element -> BuiltinBLS12_381_G2_Element
BuiltinBLS12_381_G2_Element
instance HasFromBuiltin BuiltinBLS12_381_G2_Element where
  type FromBuiltin BuiltinBLS12_381_G2_Element = BLS12_381.G2.Element
  fromBuiltin :: BuiltinBLS12_381_G2_Element
-> FromBuiltin BuiltinBLS12_381_G2_Element
fromBuiltin (BuiltinBLS12_381_G2_Element Element
a) = Element
FromBuiltin BuiltinBLS12_381_G2_Element
a

instance HasToBuiltin BLS12_381.Pairing.MlResult where
  type ToBuiltin BLS12_381.Pairing.MlResult = BuiltinBLS12_381_MlResult
  toBuiltin :: MlResult -> ToBuiltin MlResult
toBuiltin = (MlResult -> BuiltinBLS12_381_MlResult)
-> MlResult -> BuiltinBLS12_381_MlResult
forall a. a -> a
useToOpaque MlResult -> BuiltinBLS12_381_MlResult
BuiltinBLS12_381_MlResult
instance HasFromBuiltin BuiltinBLS12_381_MlResult where
  type FromBuiltin BuiltinBLS12_381_MlResult = BLS12_381.Pairing.MlResult
  fromBuiltin :: BuiltinBLS12_381_MlResult -> FromBuiltin BuiltinBLS12_381_MlResult
fromBuiltin (BuiltinBLS12_381_MlResult MlResult
a) = MlResult
FromBuiltin BuiltinBLS12_381_MlResult
a