-- |Safe overrides of the methods of class 'Integral'.
module Incipit.Integral where

import Data.Eq (Eq)
import Data.Maybe (Maybe (Just, Nothing))
import GHC.Num (Num)
import qualified GHC.Real as Real
import GHC.Real (Integral)

-- |Helper for operations that return 'Nothing' if the second operand is @0@.
safeOp ::
  Eq a =>
  Num a =>
  (a -> a -> b) ->
  a ->
  a ->
  Maybe b
safeOp :: forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> b
op a
n = \case
  a
0 ->
    Maybe b
forall a. Maybe a
Nothing
  a
d ->
    b -> Maybe b
forall a. a -> Maybe a
Just (a -> a -> b
op a
n a
d)
{-# inline safeOp #-}

-- | integer division truncated toward zero
quot ::
  Integral a =>
  a ->
  a ->
  Maybe a
quot :: forall a. Integral a => a -> a -> Maybe a
quot =
  (a -> a -> a) -> a -> a -> Maybe a
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> a
forall a. Integral a => a -> a -> a
Real.quot
{-# inline quot #-}

-- | integer remainder, satisfying
--
-- > (x `quot` y)*y + (x `rem` y) == x
rem ::
  Integral a =>
  a ->
  a ->
  Maybe a
rem :: forall a. Integral a => a -> a -> Maybe a
rem =
  (a -> a -> a) -> a -> a -> Maybe a
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> a
forall a. Integral a => a -> a -> a
Real.rem
{-# inline rem #-}

-- | integer division truncated toward negative infinity
div ::
  Integral a =>
  a ->
  a ->
  Maybe a
div :: forall a. Integral a => a -> a -> Maybe a
div =
  (a -> a -> a) -> a -> a -> Maybe a
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> a
forall a. Integral a => a -> a -> a
Real.div
{-# inline div #-}

-- | integer modulus, satisfying
--
-- > (x `div` y)*y + (x `mod` y) == x
mod ::
  Integral a =>
  a ->
  a ->
  Maybe a
mod :: forall a. Integral a => a -> a -> Maybe a
mod =
  (a -> a -> a) -> a -> a -> Maybe a
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> a
forall a. Integral a => a -> a -> a
Real.mod
{-# inline mod #-}

-- | simultaneous 'quot' and 'rem'
quotRem ::
  Integral a =>
  a ->
  a ->
  Maybe (a, a)
quotRem :: forall a. Integral a => a -> a -> Maybe (a, a)
quotRem =
  (a -> a -> (a, a)) -> a -> a -> Maybe (a, a)
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
Real.quotRem
{-# inline quotRem #-}

-- | simultaneous 'div' and 'mod'
divMod ::
  Integral a =>
  a ->
  a ->
  Maybe (a, a)
divMod :: forall a. Integral a => a -> a -> Maybe (a, a)
divMod =
  (a -> a -> (a, a)) -> a -> a -> Maybe (a, a)
forall a b. (Eq a, Num a) => (a -> a -> b) -> a -> a -> Maybe b
safeOp a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
Real.divMod
{-# inline divMod #-}