{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Test.Cardano.Ledger.Core.Rational where

import Cardano.Ledger.BaseTypes (
  BoundedRational (..),
  NonNegativeInterval,
  PositiveInterval,
  PositiveUnitInterval,
  UnitInterval,
  boundRational,
 )
import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy (..))
import qualified Data.Ratio
import Data.Typeable (Typeable, typeRep)
import GHC.Stack (HasCallStack)

unsafeBoundRational :: forall r. (HasCallStack, Typeable r, BoundedRational r) => Rational -> r
unsafeBoundRational :: forall r.
(HasCallStack, Typeable r, BoundedRational r) =>
Rational -> r
unsafeBoundRational Rational
x = r -> Maybe r -> r
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> r
forall a. HasCallStack => [Char] -> a
error [Char]
errMessage) (Maybe r -> r) -> Maybe r -> r
forall a b. (a -> b) -> a -> b
$ Rational -> Maybe r
forall r. BoundedRational r => Rational -> Maybe r
boundRational Rational
x
  where
    errMessage :: [Char]
errMessage = TypeRep -> [Char]
forall a. Show a => a -> [Char]
show (Proxy r -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy r
forall {k} (t :: k). Proxy t
Proxy :: Proxy r)) [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
" is out of bounds: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Rational -> [Char]
forall a. Show a => a -> [Char]
show Rational
x

-- | polymorphic rationals that agree with the Show instances of UnitInterval
-- and friends.
class IsRatio r where
  (%!) :: HasCallStack => Integer -> Integer -> r
  default (%!) :: (HasCallStack, Typeable r, BoundedRational r) => Integer -> Integer -> r
  Integer
n %! Integer
d = Rational -> r
forall r.
(HasCallStack, Typeable r, BoundedRational r) =>
Rational -> r
unsafeBoundRational (Rational -> r) -> Rational -> r
forall a b. (a -> b) -> a -> b
$ Integer
n Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
Data.Ratio.% Integer
d

instance IsRatio UnitInterval

instance IsRatio Rational where
  %! :: HasCallStack => Integer -> Integer -> Rational
(%!) = Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
(Data.Ratio.%)

instance IsRatio NonNegativeInterval

instance IsRatio PositiveInterval

instance IsRatio PositiveUnitInterval