-- | Conversions from 'Data.Fixed.Fixed'.
module Unwitch.Convert.Fixed
  ( fromInteger
  , toInteger
  , toRational
  , toFixed
  , toDouble
  )
where

import Data.Fixed (Fixed, HasResolution)
import Data.Ratio (denominator, numerator)
import qualified Prelude
import Prelude hiding (fromInteger, toInteger, toRational)

-- | Converts an Integer to a Fixed value. Infallible.
fromInteger :: (HasResolution a) => Integer -> Fixed a
fromInteger :: forall a. HasResolution a => Integer -> Fixed a
fromInteger = Integer -> Fixed a
forall a. Num a => Integer -> a
Prelude.fromInteger

-- | Converts a Fixed value to Integer, succeeding only if there is
-- no fractional part (i.e. the value is a whole number).
toInteger :: (HasResolution a) => Fixed a -> Maybe Integer
toInteger :: forall a. HasResolution a => Fixed a -> Maybe Integer
toInteger Fixed a
fixed =
  let r :: Rational
r = Fixed a -> Rational
forall a. Real a => a -> Rational
Prelude.toRational Fixed a
fixed
  in if Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1
     then Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Integer -> Maybe Integer) -> Integer -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r
     else Maybe Integer
forall a. Maybe a
Nothing

-- | Converts a Fixed value to Rational. Infallible, exact.
toRational :: (HasResolution a) => Fixed a -> Rational
toRational :: forall a. HasResolution a => Fixed a -> Rational
toRational = Fixed a -> Rational
forall a. Real a => a -> Rational
Prelude.toRational

-- | Converts between Fixed types with potentially different resolutions.
-- Succeeds only if the value can be exactly represented in the target resolution.
toFixed :: (HasResolution a, HasResolution b) => Fixed a -> Maybe (Fixed b)
toFixed :: forall a b.
(HasResolution a, HasResolution b) =>
Fixed a -> Maybe (Fixed b)
toFixed Fixed a
source =
  let r :: Rational
r = Fixed a -> Rational
forall a. Real a => a -> Rational
Prelude.toRational Fixed a
source
      target :: Fixed b
target = Rational -> Fixed b
forall a. Fractional a => Rational -> a
Prelude.fromRational Rational
r
  in if Fixed b -> Rational
forall a. Real a => a -> Rational
Prelude.toRational Fixed b
target Rational -> Rational -> Bool
forall a. Eq a => a -> a -> Bool
== Rational
r
     then Fixed b -> Maybe (Fixed b)
forall a. a -> Maybe a
Just Fixed b
target
     else Maybe (Fixed b)
forall a. Maybe a
Nothing

-- | Converts a Fixed value to Double. Infallible, but may lose precision
-- for values that cannot be exactly represented as a Double.
toDouble :: (HasResolution a) => Fixed a -> Double
toDouble :: forall a. HasResolution a => Fixed a -> Double
toDouble = Rational -> Double
forall a. Fractional a => Rational -> a
Prelude.fromRational (Rational -> Double) -> (Fixed a -> Rational) -> Fixed a -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fixed a -> Rational
forall a. Real a => a -> Rational
Prelude.toRational