-- editorconfig-checker-disable-file
-- | Same representation as Tx.Ratio but uses a different BuiltinData encoding
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns      #-}
module PlutusTx.NonCanonicalRational
    ( NonCanonicalRational (..)
    ) where

import PlutusTx as Tx
import PlutusTx.Builtins as B
import PlutusTx.Builtins.Internal as BI
import PlutusTx.Ratio as Tx
import PlutusTx.Trace (traceError)

-- We agreed to have a different BuiltinData encoding for Rationals for the ConstitutionScript,
-- other than the canonical encoding for datatypes.
-- This wrapper overloads the ToData to this agreed-upon encoding, for testing and benchmarking.
newtype NonCanonicalRational = NonCanonicalRational Tx.Rational

instance ToData NonCanonicalRational where
  {-# INLINABLE toBuiltinData #-}
  toBuiltinData :: NonCanonicalRational -> BuiltinData
toBuiltinData (NonCanonicalRational Rational
tx) =
    let num :: Integer
num = Rational -> Integer
Tx.numerator Rational
tx
        den :: Integer
den = Rational -> Integer
Tx.denominator Rational
tx
    in [Integer] -> BuiltinData
forall a. ToData a => a -> BuiltinData
toBuiltinData [Integer
num,Integer
den]

instance UnsafeFromData NonCanonicalRational where
  {-# INLINABLE unsafeFromBuiltinData #-}
  unsafeFromBuiltinData :: BuiltinData -> NonCanonicalRational
unsafeFromBuiltinData (BuiltinData -> BuiltinList BuiltinData
BI.unsafeDataAsList -> BuiltinList BuiltinData
bl) =
        -- this is the fastest way I found to convert to Rational
        let bl' :: BuiltinList BuiltinData
bl' = BuiltinList BuiltinData -> BuiltinList BuiltinData
forall a. BuiltinList a -> BuiltinList a
BI.tail BuiltinList BuiltinData
bl
        in BuiltinBool
-> (() -> NonCanonicalRational)
-> (() -> NonCanonicalRational)
-> ()
-> NonCanonicalRational
forall a. BuiltinBool -> a -> a -> a
BI.ifThenElse (BuiltinList BuiltinData -> BuiltinBool
forall a. BuiltinList a -> BuiltinBool
BI.null (BuiltinList BuiltinData -> BuiltinList BuiltinData
forall a. BuiltinList a -> BuiltinList a
BI.tail BuiltinList BuiltinData
bl'))
            (\() -> Rational -> NonCanonicalRational
NonCanonicalRational (Integer -> Integer -> Rational
Tx.unsafeRatio (BuiltinData -> Integer
B.unsafeDataAsI (BuiltinList BuiltinData -> BuiltinData
forall a. BuiltinList a -> a
BI.head BuiltinList BuiltinData
bl)) (BuiltinData -> Integer
B.unsafeDataAsI (BuiltinList BuiltinData -> BuiltinData
forall a. BuiltinList a -> a
BI.head BuiltinList BuiltinData
bl'))))
            (\() -> BuiltinString -> NonCanonicalRational
forall a. BuiltinString -> a
traceError BuiltinString
"A Rational had too many list components")
           ()