{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
-- editorconfig-checker-disable-file
{-# LANGUAGE NoImplicitPrelude #-}

-- | Same representation as Tx.Ratio but uses a different BuiltinData encoding
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
  {-# INLINEABLE 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
  {-# INLINEABLE 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 Bool
-> (() -> NonCanonicalRational)
-> (() -> NonCanonicalRational)
-> ()
-> NonCanonicalRational
forall a. Bool -> a -> a -> a
BI.ifThenElse
          (BuiltinList BuiltinData -> Bool
forall a. BuiltinList a -> Bool
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")
          ()