-- editorconfig-checker-disable-file
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE EmptyCase            #-}
{-# LANGUAGE KindSignatures       #-}
{-# LANGUAGE LambdaCase           #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-specialise #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
module PlutusTx.IsData.Class where

import Prelude qualified as Haskell (Int, error)

import PlutusCore.Data qualified as PLC
import PlutusTx.Base
import PlutusTx.Builtins as Builtins
import PlutusTx.Builtins.Internal (BuiltinData (..))
import PlutusTx.Builtins.Internal qualified as BI
import PlutusTx.Maybe (Maybe (..))

import PlutusTx.Applicative
import PlutusTx.ErrorCodes
import PlutusTx.Trace

import Data.Kind
import Data.Void

import GHC.TypeLits (ErrorMessage (..), TypeError)


{- HLINT ignore -}

-- | A typeclass for types that can be converted to and from 'BuiltinData'.
class ToData (a :: Type) where
    -- | Convert a value to 'BuiltinData'.
    toBuiltinData :: a -> BuiltinData

class FromData (a :: Type) where
    -- TODO: this should probably provide some kind of diagnostics
    -- | Convert a value from 'BuiltinData', returning 'Nothing' if this fails.
    fromBuiltinData :: BuiltinData -> Maybe a

class UnsafeFromData (a :: Type) where
    -- | Convert a value from 'BuiltinData', calling 'error' if this fails.
    -- This is typically much faster than 'fromBuiltinData'.
    --
    -- When implementing this function, make sure to call 'unsafeFromBuiltinData'
    -- rather than 'fromBuiltinData' when converting substructures!
    --
    -- This is a simple type without any validation, __use with caution__.
    unsafeFromBuiltinData :: BuiltinData -> a

instance ToData BuiltinData where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: BuiltinData -> BuiltinData
toBuiltinData = BuiltinData -> BuiltinData
forall a. a -> a
id
instance FromData BuiltinData where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe BuiltinData
fromBuiltinData BuiltinData
d = BuiltinData -> Maybe BuiltinData
forall a. a -> Maybe a
Just BuiltinData
d
instance UnsafeFromData BuiltinData where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> BuiltinData
unsafeFromBuiltinData BuiltinData
d = BuiltinData
d

instance (TypeError ('Text "Int is not supported, use Integer instead"))
    => ToData Haskell.Int where
    toBuiltinData :: Int -> BuiltinData
toBuiltinData = [Char] -> Int -> BuiltinData
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"
instance (TypeError ('Text "Int is not supported, use Integer instead"))
    => FromData Haskell.Int where
    fromBuiltinData :: BuiltinData -> Maybe Int
fromBuiltinData = [Char] -> BuiltinData -> Maybe Int
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"
instance (TypeError ('Text "Int is not supported, use Integer instead"))
    => UnsafeFromData Haskell.Int where
    unsafeFromBuiltinData :: BuiltinData -> Int
unsafeFromBuiltinData = [Char] -> BuiltinData -> Int
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"

instance ToData Integer where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: Integer -> BuiltinData
toBuiltinData Integer
i = Integer -> BuiltinData
mkI Integer
i
instance FromData Integer where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe Integer
fromBuiltinData BuiltinData
d = BuiltinData
-> (Integer -> BuiltinList BuiltinData -> Maybe Integer)
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData)
    -> Maybe Integer)
-> (BuiltinList BuiltinData -> Maybe Integer)
-> (Integer -> Maybe Integer)
-> (BuiltinByteString -> Maybe Integer)
-> Maybe Integer
forall r.
BuiltinData
-> (Integer -> BuiltinList BuiltinData -> r)
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData) -> r)
-> (BuiltinList BuiltinData -> r)
-> (Integer -> r)
-> (BuiltinByteString -> r)
-> r
matchData' BuiltinData
d (\Integer
_ BuiltinList BuiltinData
_ -> Maybe Integer
forall a. Maybe a
Nothing) (Maybe Integer
-> BuiltinList (BuiltinPair BuiltinData BuiltinData)
-> Maybe Integer
forall a b. a -> b -> a
const Maybe Integer
forall a. Maybe a
Nothing) (Maybe Integer -> BuiltinList BuiltinData -> Maybe Integer
forall a b. a -> b -> a
const Maybe Integer
forall a. Maybe a
Nothing) (\Integer
i -> Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
i) (Maybe Integer -> BuiltinByteString -> Maybe Integer
forall a b. a -> b -> a
const Maybe Integer
forall a. Maybe a
Nothing)
instance UnsafeFromData Integer where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> Integer
unsafeFromBuiltinData = BuiltinData -> Integer
BI.unsafeDataAsI

instance ToData Builtins.BuiltinByteString where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: BuiltinByteString -> BuiltinData
toBuiltinData = BuiltinByteString -> BuiltinData
mkB
instance FromData Builtins.BuiltinByteString where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe BuiltinByteString
fromBuiltinData BuiltinData
d = BuiltinData
-> (Integer -> BuiltinList BuiltinData -> Maybe BuiltinByteString)
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData)
    -> Maybe BuiltinByteString)
-> (BuiltinList BuiltinData -> Maybe BuiltinByteString)
-> (Integer -> Maybe BuiltinByteString)
-> (BuiltinByteString -> Maybe BuiltinByteString)
-> Maybe BuiltinByteString
forall r.
BuiltinData
-> (Integer -> BuiltinList BuiltinData -> r)
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData) -> r)
-> (BuiltinList BuiltinData -> r)
-> (Integer -> r)
-> (BuiltinByteString -> r)
-> r
matchData' BuiltinData
d (\Integer
_ BuiltinList BuiltinData
_ -> Maybe BuiltinByteString
forall a. Maybe a
Nothing) (Maybe BuiltinByteString
-> BuiltinList (BuiltinPair BuiltinData BuiltinData)
-> Maybe BuiltinByteString
forall a b. a -> b -> a
const Maybe BuiltinByteString
forall a. Maybe a
Nothing) (Maybe BuiltinByteString
-> BuiltinList BuiltinData -> Maybe BuiltinByteString
forall a b. a -> b -> a
const Maybe BuiltinByteString
forall a. Maybe a
Nothing) (Maybe BuiltinByteString -> Integer -> Maybe BuiltinByteString
forall a b. a -> b -> a
const Maybe BuiltinByteString
forall a. Maybe a
Nothing) (\BuiltinByteString
b -> BuiltinByteString -> Maybe BuiltinByteString
forall a. a -> Maybe a
Just BuiltinByteString
b)
instance UnsafeFromData Builtins.BuiltinByteString where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> BuiltinByteString
unsafeFromBuiltinData = BuiltinData -> BuiltinByteString
BI.unsafeDataAsB

instance ToData a => ToData [a] where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: [a] -> BuiltinData
toBuiltinData [a]
l = BuiltinList BuiltinData -> BuiltinData
BI.mkList ([a] -> BuiltinList BuiltinData
mapToBuiltin [a]
l)
        where
          {-# INLINE mapToBuiltin #-}
          mapToBuiltin :: [a] -> BI.BuiltinList BI.BuiltinData
          mapToBuiltin :: [a] -> BuiltinList BuiltinData
mapToBuiltin = [a] -> BuiltinList BuiltinData
go
            where
                go :: [a] -> BI.BuiltinList BI.BuiltinData
                go :: [a] -> BuiltinList BuiltinData
go []     = BuiltinList BuiltinData
forall arep. MkNil arep => BuiltinList arep
mkNil
                go (a
x:[a]
xs) = BuiltinData -> BuiltinList BuiltinData -> BuiltinList BuiltinData
forall a. a -> BuiltinList a -> BuiltinList a
BI.mkCons (a -> BuiltinData
forall a. ToData a => a -> BuiltinData
toBuiltinData a
x) ([a] -> BuiltinList BuiltinData
go [a]
xs)
instance FromData a => FromData [a] where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe [a]
fromBuiltinData BuiltinData
d =
        BuiltinData
-> (Integer -> BuiltinList BuiltinData -> Maybe [a])
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData) -> Maybe [a])
-> (BuiltinList BuiltinData -> Maybe [a])
-> (Integer -> Maybe [a])
-> (BuiltinByteString -> Maybe [a])
-> Maybe [a]
forall r.
BuiltinData
-> (Integer -> BuiltinList BuiltinData -> r)
-> (BuiltinList (BuiltinPair BuiltinData BuiltinData) -> r)
-> (BuiltinList BuiltinData -> r)
-> (Integer -> r)
-> (BuiltinByteString -> r)
-> r
matchData'
        BuiltinData
d
        (\Integer
_ BuiltinList BuiltinData
_ -> Maybe [a]
forall a. Maybe a
Nothing)
        (Maybe [a]
-> BuiltinList (BuiltinPair BuiltinData BuiltinData) -> Maybe [a]
forall a b. a -> b -> a
const Maybe [a]
forall a. Maybe a
Nothing)
        BuiltinList BuiltinData -> Maybe [a]
traverseFromBuiltin
        (Maybe [a] -> Integer -> Maybe [a]
forall a b. a -> b -> a
const Maybe [a]
forall a. Maybe a
Nothing)
        (Maybe [a] -> BuiltinByteString -> Maybe [a]
forall a b. a -> b -> a
const Maybe [a]
forall a. Maybe a
Nothing)
        where
          {-# INLINE traverseFromBuiltin #-}
          traverseFromBuiltin :: BI.BuiltinList BI.BuiltinData -> Maybe [a]
          traverseFromBuiltin :: BuiltinList BuiltinData -> Maybe [a]
traverseFromBuiltin = BuiltinList BuiltinData -> Maybe [a]
go
            where
                go :: BI.BuiltinList BI.BuiltinData -> Maybe [a]
                go :: BuiltinList BuiltinData -> Maybe [a]
go BuiltinList BuiltinData
l = BuiltinList BuiltinData
-> (() -> Maybe [a]) -> (() -> Maybe [a]) -> () -> Maybe [a]
forall a b. BuiltinList a -> b -> b -> b
BI.chooseList BuiltinList BuiltinData
l (Maybe [a] -> () -> Maybe [a]
forall a b. a -> b -> a
const ([a] -> Maybe [a]
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [])) (\()
_ -> (a -> [a] -> [a]) -> Maybe a -> Maybe [a] -> Maybe [a]
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (:) (BuiltinData -> Maybe a
forall a. FromData a => BuiltinData -> Maybe a
fromBuiltinData (BuiltinList BuiltinData -> BuiltinData
forall a. BuiltinList a -> a
BI.head BuiltinList BuiltinData
l)) (BuiltinList BuiltinData -> Maybe [a]
go (BuiltinList BuiltinData -> BuiltinList BuiltinData
forall a. BuiltinList a -> BuiltinList a
BI.tail BuiltinList BuiltinData
l))) ()
instance UnsafeFromData a => UnsafeFromData [a] where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> [a]
unsafeFromBuiltinData BuiltinData
d = BuiltinList BuiltinData -> [a]
mapFromBuiltin (BuiltinData -> BuiltinList BuiltinData
BI.unsafeDataAsList BuiltinData
d)
        where
          {-# INLINE mapFromBuiltin #-}
          mapFromBuiltin :: BI.BuiltinList BI.BuiltinData -> [a]
          mapFromBuiltin :: BuiltinList BuiltinData -> [a]
mapFromBuiltin = BuiltinList BuiltinData -> [a]
go
            where
                go :: BI.BuiltinList BI.BuiltinData -> [a]
                go :: BuiltinList BuiltinData -> [a]
go BuiltinList BuiltinData
l = BuiltinList BuiltinData -> (() -> [a]) -> (() -> [a]) -> () -> [a]
forall a b. BuiltinList a -> b -> b -> b
BI.chooseList BuiltinList BuiltinData
l ([a] -> () -> [a]
forall a b. a -> b -> a
const []) (\()
_ -> BuiltinData -> a
forall a. UnsafeFromData a => BuiltinData -> a
unsafeFromBuiltinData (BuiltinList BuiltinData -> BuiltinData
forall a. BuiltinList a -> a
BI.head BuiltinList BuiltinData
l) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: BuiltinList BuiltinData -> [a]
go (BuiltinList BuiltinData -> BuiltinList BuiltinData
forall a. BuiltinList a -> BuiltinList a
BI.tail BuiltinList BuiltinData
l)) ()

instance ToData Void where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: Void -> BuiltinData
toBuiltinData = \case {}
instance FromData Void where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe Void
fromBuiltinData BuiltinData
_ = Maybe Void
forall a. Maybe a
Nothing
instance UnsafeFromData Void where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> Void
unsafeFromBuiltinData BuiltinData
_ = BuiltinString -> Void
forall a. BuiltinString -> a
traceError BuiltinString
voidIsNotSupportedError

{- | For the BLS12-381 G1 and G2 types we use the `compress` functions to convert
   to a ByteString and then encode that as Data as usual.  We have to be more
   careful going the other way because we decode a Data object to (possibly) get
   a BuiltinByteString and then uncompress the underlying ByteString to get a
   group element.  However uncompression can fail so we have to check what
   happens: we don't use bls12_381_G?_uncompress because that invokes `error` if
   something goes wrong (but we do use it for unsafeFromData).
-}
instance ToData Builtins.BuiltinBLS12_381_G1_Element where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: BuiltinBLS12_381_G1_Element -> BuiltinData
toBuiltinData = BuiltinByteString -> BuiltinData
forall a. ToData a => a -> BuiltinData
toBuiltinData (BuiltinByteString -> BuiltinData)
-> (BuiltinBLS12_381_G1_Element -> BuiltinByteString)
-> BuiltinBLS12_381_G1_Element
-> BuiltinData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuiltinBLS12_381_G1_Element -> BuiltinByteString
Builtins.bls12_381_G1_compress
instance FromData Builtins.BuiltinBLS12_381_G1_Element where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe BuiltinBLS12_381_G1_Element
fromBuiltinData BuiltinData
d =
        case BuiltinData -> Maybe BuiltinByteString
forall a. FromData a => BuiltinData -> Maybe a
fromBuiltinData BuiltinData
d of
          Maybe BuiltinByteString
Nothing -> Maybe BuiltinBLS12_381_G1_Element
forall a. Maybe a
Nothing
          Just BuiltinByteString
bs -> BuiltinBLS12_381_G1_Element -> Maybe BuiltinBLS12_381_G1_Element
forall a. a -> Maybe a
Just (BuiltinBLS12_381_G1_Element -> Maybe BuiltinBLS12_381_G1_Element)
-> BuiltinBLS12_381_G1_Element -> Maybe BuiltinBLS12_381_G1_Element
forall a b. (a -> b) -> a -> b
$ BuiltinByteString -> BuiltinBLS12_381_G1_Element
bls12_381_G1_uncompress BuiltinByteString
bs
instance UnsafeFromData Builtins.BuiltinBLS12_381_G1_Element where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> BuiltinBLS12_381_G1_Element
unsafeFromBuiltinData = BuiltinByteString -> BuiltinBLS12_381_G1_Element
Builtins.bls12_381_G1_uncompress (BuiltinByteString -> BuiltinBLS12_381_G1_Element)
-> (BuiltinData -> BuiltinByteString)
-> BuiltinData
-> BuiltinBLS12_381_G1_Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuiltinData -> BuiltinByteString
forall a. UnsafeFromData a => BuiltinData -> a
unsafeFromBuiltinData

instance ToData Builtins.BuiltinBLS12_381_G2_Element where
    {-# INLINABLE toBuiltinData #-}
    toBuiltinData :: BuiltinBLS12_381_G2_Element -> BuiltinData
toBuiltinData = BuiltinByteString -> BuiltinData
forall a. ToData a => a -> BuiltinData
toBuiltinData (BuiltinByteString -> BuiltinData)
-> (BuiltinBLS12_381_G2_Element -> BuiltinByteString)
-> BuiltinBLS12_381_G2_Element
-> BuiltinData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuiltinBLS12_381_G2_Element -> BuiltinByteString
Builtins.bls12_381_G2_compress
instance FromData Builtins.BuiltinBLS12_381_G2_Element where
    {-# INLINABLE fromBuiltinData #-}
    fromBuiltinData :: BuiltinData -> Maybe BuiltinBLS12_381_G2_Element
fromBuiltinData BuiltinData
d =
        case BuiltinData -> Maybe BuiltinByteString
forall a. FromData a => BuiltinData -> Maybe a
fromBuiltinData BuiltinData
d of
          Maybe BuiltinByteString
Nothing -> Maybe BuiltinBLS12_381_G2_Element
forall a. Maybe a
Nothing
          Just BuiltinByteString
bs -> BuiltinBLS12_381_G2_Element -> Maybe BuiltinBLS12_381_G2_Element
forall a. a -> Maybe a
Just (BuiltinBLS12_381_G2_Element -> Maybe BuiltinBLS12_381_G2_Element)
-> BuiltinBLS12_381_G2_Element -> Maybe BuiltinBLS12_381_G2_Element
forall a b. (a -> b) -> a -> b
$ BuiltinByteString -> BuiltinBLS12_381_G2_Element
bls12_381_G2_uncompress BuiltinByteString
bs
instance UnsafeFromData Builtins.BuiltinBLS12_381_G2_Element where
    {-# INLINABLE unsafeFromBuiltinData #-}
    unsafeFromBuiltinData :: BuiltinData -> BuiltinBLS12_381_G2_Element
unsafeFromBuiltinData = BuiltinByteString -> BuiltinBLS12_381_G2_Element
Builtins.bls12_381_G2_uncompress (BuiltinByteString -> BuiltinBLS12_381_G2_Element)
-> (BuiltinData -> BuiltinByteString)
-> BuiltinData
-> BuiltinBLS12_381_G2_Element
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuiltinData -> BuiltinByteString
forall a. UnsafeFromData a => BuiltinData -> a
unsafeFromBuiltinData

{- | We do not provide instances of any of these classes for
   BuiltinBLS12_381_MlResult since there is no serialisation format: we expect
   that values of that type will only occur as the result of on-chain
   computations.
-}
instance (TypeError ('Text "toBuiltinData is not supported for BuiltinBLS12_381_MlResult"))
    => ToData Builtins.BuiltinBLS12_381_MlResult where
    toBuiltinData :: BuiltinBLS12_381_MlResult -> BuiltinData
toBuiltinData = [Char] -> BuiltinBLS12_381_MlResult -> BuiltinData
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"
instance (TypeError ('Text "fromBuiltinData is not supported for BuiltinBLS12_381_MlResult"))
    => FromData Builtins.BuiltinBLS12_381_MlResult where
    fromBuiltinData :: BuiltinData -> Maybe BuiltinBLS12_381_MlResult
fromBuiltinData = [Char] -> BuiltinData -> Maybe BuiltinBLS12_381_MlResult
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"
instance (TypeError ('Text "unsafeFromBuiltinData is not supported for BuiltinBLS12_381_MlResult"))
    => UnsafeFromData Builtins.BuiltinBLS12_381_MlResult where
    unsafeFromBuiltinData :: BuiltinData -> BuiltinBLS12_381_MlResult
unsafeFromBuiltinData = [Char] -> BuiltinData -> BuiltinBLS12_381_MlResult
forall a. HasCallStack => [Char] -> a
Haskell.error [Char]
"unsupported"

-- | Convert a value to 'PLC.Data'.
toData :: (ToData a) => a -> PLC.Data
toData :: forall a. ToData a => a -> Data
toData a
a = BuiltinData -> Data
builtinDataToData (a -> BuiltinData
forall a. ToData a => a -> BuiltinData
toBuiltinData a
a)

-- | Convert a value from 'PLC.Data', returning 'Nothing' if this fails.
fromData :: (FromData a) => PLC.Data -> Maybe a
fromData :: forall a. FromData a => Data -> Maybe a
fromData Data
d = BuiltinData -> Maybe a
forall a. FromData a => BuiltinData -> Maybe a
fromBuiltinData (Data -> BuiltinData
BuiltinData Data
d)

-- | Convert a value from 'PLC.Data', throwing if this fails.
unsafeFromData :: (UnsafeFromData a) => PLC.Data -> a
unsafeFromData :: forall a. UnsafeFromData a => Data -> a
unsafeFromData Data
d = BuiltinData -> a
forall a. UnsafeFromData a => BuiltinData -> a
unsafeFromBuiltinData (Data -> BuiltinData
BuiltinData Data
d)