module PlutusTx.Ord.Class
  ( Ord (..)
  , Ordering (..)
  ) where

{-
  We export off-chain Haskell's Ordering type as on-chain Plutus's
  Ordering type since they are the same.
-}

import PlutusTx.Bool (Bool (..))
import PlutusTx.Builtins qualified as Builtins
import PlutusTx.Eq.Class (Eq (..))
import Prelude (Ordering (..))

infix 4 <, <=, >, >=

-- Copied from the GHC definition

{-| The 'Ord' class is used for totally ordered datatypes.

Minimal complete definition: either 'compare' or '<='.
Using 'compare' can be more efficient for complex types. -}
class Eq a => Ord a where
  compare :: a -> a -> Ordering
  (<), (<=), (>), (>=) :: a -> a -> Bool
  max, min :: a -> a -> a

  {-# INLINEABLE compare #-}
  compare a
x a
y =
    if a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y
      then Ordering
EQ
      -- NB: must be '<=' not '<' to validate the
      -- above claim about the minimal things that
      -- can be defined for an instance of Ord:
      else
        if a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
y
          then Ordering
LT
          else Ordering
GT

  {-# INLINEABLE (<) #-}
  a
x < a
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
y of Ordering
LT -> Bool
True; Ordering
_ -> Bool
False
  {-# INLINEABLE (<=) #-}
  a
x <= a
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
y of Ordering
GT -> Bool
False; Ordering
_ -> Bool
True
  {-# INLINEABLE (>) #-}
  a
x > a
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
y of Ordering
GT -> Bool
True; Ordering
_ -> Bool
False
  {-# INLINEABLE (>=) #-}
  a
x >= a
y = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
y of Ordering
LT -> Bool
False; Ordering
_ -> Bool
True

  -- These two default methods use '<=' rather than 'compare'
  -- because the latter is often more expensive
  {-# INLINEABLE max #-}
  max a
x a
y = if a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
y then a
y else a
x
  {-# INLINEABLE min #-}
  min a
x a
y = if a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
y then a
x else a
y
  {-# MINIMAL compare | (<=) #-}

instance Ord Builtins.Integer where
  {-# INLINEABLE (<) #-}
  < :: Integer -> Integer -> Bool
(<) = Integer -> Integer -> Bool
Builtins.lessThanInteger
  {-# INLINEABLE (<=) #-}
  <= :: Integer -> Integer -> Bool
(<=) = Integer -> Integer -> Bool
Builtins.lessThanEqualsInteger
  {-# INLINEABLE (>) #-}
  > :: Integer -> Integer -> Bool
(>) = Integer -> Integer -> Bool
Builtins.greaterThanInteger
  {-# INLINEABLE (>=) #-}
  >= :: Integer -> Integer -> Bool
(>=) = Integer -> Integer -> Bool
Builtins.greaterThanEqualsInteger

instance Ord Builtins.BuiltinByteString where
  {-# INLINEABLE (<) #-}
  < :: BuiltinByteString -> BuiltinByteString -> Bool
(<) = BuiltinByteString -> BuiltinByteString -> Bool
Builtins.lessThanByteString
  {-# INLINEABLE (<=) #-}
  <= :: BuiltinByteString -> BuiltinByteString -> Bool
(<=) = BuiltinByteString -> BuiltinByteString -> Bool
Builtins.lessThanEqualsByteString
  {-# INLINEABLE (>) #-}
  > :: BuiltinByteString -> BuiltinByteString -> Bool
(>) = BuiltinByteString -> BuiltinByteString -> Bool
Builtins.greaterThanByteString
  {-# INLINEABLE (>=) #-}
  >= :: BuiltinByteString -> BuiltinByteString -> Bool
(>=) = BuiltinByteString -> BuiltinByteString -> Bool
Builtins.greaterThanEqualsByteString