{- |
Module      : Singular.Registry.Wire.Primitive
Description : Primitive registry wire values, their codecs, and the shared Data helpers
License     : Apache-2.0

The leaf of the registry wire family: the token identifier, output
reference and root values every other wire module builds on, their
'ToData'\/'FromData'\/'UnsafeFromData' codecs, and the 'Data'
conversion helpers the codecs share. Depends on no sibling; nothing
here is importable by a caller — the public surface is the
"Singular.Registry.Types" facade.
-}
module Singular.Registry.Wire.Primitive
    ( -- * On-chain domain types (Plutus primitives)
      OnChainTokenId (..)
    , OnChainTxOutRef (..)
    , OnChainRoot (..)

      -- * Helpers for manual Data construction
    , mkD
    , unD
    , bsToD
    , bsFromD
    , bbsToD
    , bbsFromD
    ) where

import Data.ByteString (ByteString)
import PlutusCore.Data (Data (..))
import PlutusTx.Builtins.Internal
    ( BuiltinByteString (..)
    , BuiltinData (..)
    )
import PlutusTx.IsData.Class
    ( FromData (..)
    , ToData (..)
    , UnsafeFromData (..)
    )

{- | On-chain token identifier (asset name as raw
bytes). Matches Aiken @lib\/TokenId@.
-}
newtype OnChainTokenId = OnChainTokenId
    { OnChainTokenId -> BuiltinByteString
unOnChainTokenId :: BuiltinByteString
    }
    deriving stock (Int -> OnChainTokenId -> ShowS
[OnChainTokenId] -> ShowS
OnChainTokenId -> String
(Int -> OnChainTokenId -> ShowS)
-> (OnChainTokenId -> String)
-> ([OnChainTokenId] -> ShowS)
-> Show OnChainTokenId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OnChainTokenId -> ShowS
showsPrec :: Int -> OnChainTokenId -> ShowS
$cshow :: OnChainTokenId -> String
show :: OnChainTokenId -> String
$cshowList :: [OnChainTokenId] -> ShowS
showList :: [OnChainTokenId] -> ShowS
Show, OnChainTokenId -> OnChainTokenId -> Bool
(OnChainTokenId -> OnChainTokenId -> Bool)
-> (OnChainTokenId -> OnChainTokenId -> Bool) -> Eq OnChainTokenId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OnChainTokenId -> OnChainTokenId -> Bool
== :: OnChainTokenId -> OnChainTokenId -> Bool
$c/= :: OnChainTokenId -> OnChainTokenId -> Bool
/= :: OnChainTokenId -> OnChainTokenId -> Bool
Eq)

{- | On-chain output reference. Matches Aiken
@cardano\/transaction\/OutputReference@.
-}
data OnChainTxOutRef = OnChainTxOutRef
    { OnChainTxOutRef -> BuiltinByteString
txOutRefId :: !BuiltinByteString
    -- ^ Transaction hash (32 bytes)
    , OnChainTxOutRef -> Integer
txOutRefIdx :: !Integer
    -- ^ Output index within the transaction
    }
    deriving stock (Int -> OnChainTxOutRef -> ShowS
[OnChainTxOutRef] -> ShowS
OnChainTxOutRef -> String
(Int -> OnChainTxOutRef -> ShowS)
-> (OnChainTxOutRef -> String)
-> ([OnChainTxOutRef] -> ShowS)
-> Show OnChainTxOutRef
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OnChainTxOutRef -> ShowS
showsPrec :: Int -> OnChainTxOutRef -> ShowS
$cshow :: OnChainTxOutRef -> String
show :: OnChainTxOutRef -> String
$cshowList :: [OnChainTxOutRef] -> ShowS
showList :: [OnChainTxOutRef] -> ShowS
Show, OnChainTxOutRef -> OnChainTxOutRef -> Bool
(OnChainTxOutRef -> OnChainTxOutRef -> Bool)
-> (OnChainTxOutRef -> OnChainTxOutRef -> Bool)
-> Eq OnChainTxOutRef
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OnChainTxOutRef -> OnChainTxOutRef -> Bool
== :: OnChainTxOutRef -> OnChainTxOutRef -> Bool
$c/= :: OnChainTxOutRef -> OnChainTxOutRef -> Bool
/= :: OnChainTxOutRef -> OnChainTxOutRef -> Bool
Eq)

-- | On-chain MPF root hash (raw bytes).
newtype OnChainRoot = OnChainRoot
    { OnChainRoot -> ByteString
unOnChainRoot :: ByteString
    }
    deriving stock (Int -> OnChainRoot -> ShowS
[OnChainRoot] -> ShowS
OnChainRoot -> String
(Int -> OnChainRoot -> ShowS)
-> (OnChainRoot -> String)
-> ([OnChainRoot] -> ShowS)
-> Show OnChainRoot
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> OnChainRoot -> ShowS
showsPrec :: Int -> OnChainRoot -> ShowS
$cshow :: OnChainRoot -> String
show :: OnChainRoot -> String
$cshowList :: [OnChainRoot] -> ShowS
showList :: [OnChainRoot] -> ShowS
Show, OnChainRoot -> OnChainRoot -> Bool
(OnChainRoot -> OnChainRoot -> Bool)
-> (OnChainRoot -> OnChainRoot -> Bool) -> Eq OnChainRoot
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: OnChainRoot -> OnChainRoot -> Bool
== :: OnChainRoot -> OnChainRoot -> Bool
$c/= :: OnChainRoot -> OnChainRoot -> Bool
/= :: OnChainRoot -> OnChainRoot -> Bool
Eq)

-- ---------------------------------------------------------
-- Helpers for manual Data construction
-- ---------------------------------------------------------

-- | Wrap a raw 'Data' value as 'BuiltinData'.
mkD :: Data -> BuiltinData
mkD :: Data -> BuiltinData
mkD = Data -> BuiltinData
BuiltinData

-- | Unwrap 'BuiltinData' to the raw 'Data' AST.
unD :: BuiltinData -> Data
unD :: BuiltinData -> Data
unD (BuiltinData Data
d) = Data
d

-- | Lift a 'ByteString' into a 'Data' byte-literal.
bsToD :: ByteString -> Data
bsToD :: ByteString -> Data
bsToD = ByteString -> Data
B

-- | Extract a 'ByteString' from a 'Data' byte-literal.
bsFromD :: Data -> Maybe ByteString
bsFromD :: Data -> Maybe ByteString
bsFromD (B ByteString
bs) = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
bs
bsFromD Data
_ = Maybe ByteString
forall a. Maybe a
Nothing

{- | Lift a 'BuiltinByteString' into a 'Data'
byte-literal.
-}
bbsToD :: BuiltinByteString -> Data
bbsToD :: BuiltinByteString -> Data
bbsToD (BuiltinByteString ByteString
bs) = ByteString -> Data
B ByteString
bs

{- | Extract a 'BuiltinByteString' from a 'Data'
byte-literal.
-}
bbsFromD :: Data -> Maybe BuiltinByteString
bbsFromD :: Data -> Maybe BuiltinByteString
bbsFromD (B ByteString
bs) = BuiltinByteString -> Maybe BuiltinByteString
forall a. a -> Maybe a
Just (ByteString -> BuiltinByteString
BuiltinByteString ByteString
bs)
bbsFromD Data
_ = Maybe BuiltinByteString
forall a. Maybe a
Nothing

-- ---------------------------------------------------------
-- ToData / FromData instances
-- ---------------------------------------------------------

instance ToData OnChainTokenId where
    toBuiltinData :: OnChainTokenId -> BuiltinData
toBuiltinData (OnChainTokenId BuiltinByteString
bbs) =
        Data -> BuiltinData
mkD (Data -> BuiltinData) -> Data -> BuiltinData
forall a b. (a -> b) -> a -> b
$ Integer -> [Data] -> Data
Constr Integer
0 [BuiltinByteString -> Data
bbsToD BuiltinByteString
bbs]

instance FromData OnChainTokenId where
    fromBuiltinData :: BuiltinData -> Maybe OnChainTokenId
fromBuiltinData BuiltinData
bd = case BuiltinData -> Data
unD BuiltinData
bd of
        Constr Integer
0 [Data
x] ->
            BuiltinByteString -> OnChainTokenId
OnChainTokenId (BuiltinByteString -> OnChainTokenId)
-> Maybe BuiltinByteString -> Maybe OnChainTokenId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Data -> Maybe BuiltinByteString
bbsFromD Data
x
        Data
_ -> Maybe OnChainTokenId
forall a. Maybe a
Nothing

instance UnsafeFromData OnChainTokenId where
    unsafeFromBuiltinData :: BuiltinData -> OnChainTokenId
unsafeFromBuiltinData BuiltinData
bd = case BuiltinData -> Data
unD BuiltinData
bd of
        Constr Integer
0 [Data
x] -> case Data -> Maybe BuiltinByteString
bbsFromD Data
x of
            Just BuiltinByteString
bbs -> BuiltinByteString -> OnChainTokenId
OnChainTokenId BuiltinByteString
bbs
            Maybe BuiltinByteString
_ ->
                String -> OnChainTokenId
forall a. HasCallStack => String -> a
error
                    String
"unsafeFromBuiltinData: OnChainTokenId"
        Data
_ ->
            String -> OnChainTokenId
forall a. HasCallStack => String -> a
error
                String
"unsafeFromBuiltinData: OnChainTokenId"

instance ToData OnChainTxOutRef where
    toBuiltinData :: OnChainTxOutRef -> BuiltinData
toBuiltinData OnChainTxOutRef{Integer
BuiltinByteString
txOutRefId :: OnChainTxOutRef -> BuiltinByteString
txOutRefIdx :: OnChainTxOutRef -> Integer
txOutRefId :: BuiltinByteString
txOutRefIdx :: Integer
..} =
        Data -> BuiltinData
mkD (Data -> BuiltinData) -> Data -> BuiltinData
forall a b. (a -> b) -> a -> b
$
            Integer -> [Data] -> Data
Constr
                Integer
0
                [BuiltinByteString -> Data
bbsToD BuiltinByteString
txOutRefId, Integer -> Data
I Integer
txOutRefIdx]

instance FromData OnChainTxOutRef where
    fromBuiltinData :: BuiltinData -> Maybe OnChainTxOutRef
fromBuiltinData BuiltinData
bd = case BuiltinData -> Data
unD BuiltinData
bd of
        Constr Integer
0 [Data
tid, I Integer
idx] ->
            BuiltinByteString -> Integer -> OnChainTxOutRef
OnChainTxOutRef
                (BuiltinByteString -> Integer -> OnChainTxOutRef)
-> Maybe BuiltinByteString -> Maybe (Integer -> OnChainTxOutRef)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Data -> Maybe BuiltinByteString
bbsFromD Data
tid
                Maybe (Integer -> OnChainTxOutRef)
-> Maybe Integer -> Maybe OnChainTxOutRef
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Integer -> Maybe Integer
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Integer
idx
        Data
_ -> Maybe OnChainTxOutRef
forall a. Maybe a
Nothing

instance UnsafeFromData OnChainTxOutRef where
    unsafeFromBuiltinData :: BuiltinData -> OnChainTxOutRef
unsafeFromBuiltinData BuiltinData
bd = case BuiltinData -> Data
unD BuiltinData
bd of
        Constr Integer
0 [B ByteString
tid, I Integer
idx] ->
            BuiltinByteString -> Integer -> OnChainTxOutRef
OnChainTxOutRef
                (ByteString -> BuiltinByteString
BuiltinByteString ByteString
tid)
                Integer
idx
        Data
_ ->
            String -> OnChainTxOutRef
forall a. HasCallStack => String -> a
error
                String
"unsafeFromBuiltinData: OnChainTxOutRef"

instance ToData OnChainRoot where
    toBuiltinData :: OnChainRoot -> BuiltinData
toBuiltinData (OnChainRoot ByteString
bs) = Data -> BuiltinData
mkD (Data -> BuiltinData) -> Data -> BuiltinData
forall a b. (a -> b) -> a -> b
$ ByteString -> Data
bsToD ByteString
bs

instance FromData OnChainRoot where
    fromBuiltinData :: BuiltinData -> Maybe OnChainRoot
fromBuiltinData BuiltinData
bd =
        ByteString -> OnChainRoot
OnChainRoot (ByteString -> OnChainRoot)
-> Maybe ByteString -> Maybe OnChainRoot
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Data -> Maybe ByteString
bsFromD (BuiltinData -> Data
unD BuiltinData
bd)

instance UnsafeFromData OnChainRoot where
    unsafeFromBuiltinData :: BuiltinData -> OnChainRoot
unsafeFromBuiltinData BuiltinData
bd = case BuiltinData -> Data
unD BuiltinData
bd of
        B ByteString
bs -> ByteString -> OnChainRoot
OnChainRoot ByteString
bs
        Data
_ ->
            String -> OnChainRoot
forall a. HasCallStack => String -> a
error
                String
"unsafeFromBuiltinData: OnChainRoot"