{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE ScopedTypeVariables        #-}
module Data.Avro.Schema.Decimal
( Decimal
, fromUnderlyingValue
, underlyingValue )
where

import qualified Data.BigDecimal as D
import           Data.Proxy
import           GHC.TypeLits

newtype Decimal (p :: Nat) (s :: Nat)
  = Decimal { forall (p :: Natural) (s :: Natural). Decimal p s -> BigDecimal
unDecimal :: D.BigDecimal }
  deriving (Decimal p s -> Decimal p s -> Bool
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Decimal p s -> Decimal p s -> Bool
$c/= :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
== :: Decimal p s -> Decimal p s -> Bool
$c== :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
Eq, Decimal p s -> Decimal p s -> Bool
Decimal p s -> Decimal p s -> Ordering
Decimal p s -> Decimal p s -> Decimal p s
forall (p :: Natural) (s :: Natural). Eq (Decimal p s)
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Ordering
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Decimal p s -> Decimal p s -> Decimal p s
$cmin :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
max :: Decimal p s -> Decimal p s -> Decimal p s
$cmax :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
>= :: Decimal p s -> Decimal p s -> Bool
$c>= :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
> :: Decimal p s -> Decimal p s -> Bool
$c> :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
<= :: Decimal p s -> Decimal p s -> Bool
$c<= :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
< :: Decimal p s -> Decimal p s -> Bool
$c< :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Bool
compare :: Decimal p s -> Decimal p s -> Ordering
$ccompare :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Ordering
Ord, Int -> Decimal p s -> ShowS
forall (p :: Natural) (s :: Natural). Int -> Decimal p s -> ShowS
forall (p :: Natural) (s :: Natural). [Decimal p s] -> ShowS
forall (p :: Natural) (s :: Natural). Decimal p s -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Decimal p s] -> ShowS
$cshowList :: forall (p :: Natural) (s :: Natural). [Decimal p s] -> ShowS
show :: Decimal p s -> String
$cshow :: forall (p :: Natural) (s :: Natural). Decimal p s -> String
showsPrec :: Int -> Decimal p s -> ShowS
$cshowsPrec :: forall (p :: Natural) (s :: Natural). Int -> Decimal p s -> ShowS
Show, ReadPrec [Decimal p s]
ReadPrec (Decimal p s)
ReadS [Decimal p s]
forall (p :: Natural) (s :: Natural). ReadPrec [Decimal p s]
forall (p :: Natural) (s :: Natural). ReadPrec (Decimal p s)
forall (p :: Natural) (s :: Natural). Int -> ReadS (Decimal p s)
forall (p :: Natural) (s :: Natural). ReadS [Decimal p s]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Decimal p s]
$creadListPrec :: forall (p :: Natural) (s :: Natural). ReadPrec [Decimal p s]
readPrec :: ReadPrec (Decimal p s)
$creadPrec :: forall (p :: Natural) (s :: Natural). ReadPrec (Decimal p s)
readList :: ReadS [Decimal p s]
$creadList :: forall (p :: Natural) (s :: Natural). ReadS [Decimal p s]
readsPrec :: Int -> ReadS (Decimal p s)
$creadsPrec :: forall (p :: Natural) (s :: Natural). Int -> ReadS (Decimal p s)
Read, Integer -> Decimal p s
Decimal p s -> Decimal p s
Decimal p s -> Decimal p s -> Decimal p s
forall (p :: Natural) (s :: Natural). Integer -> Decimal p s
forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> Decimal p s
$cfromInteger :: forall (p :: Natural) (s :: Natural). Integer -> Decimal p s
signum :: Decimal p s -> Decimal p s
$csignum :: forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
abs :: Decimal p s -> Decimal p s
$cabs :: forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
negate :: Decimal p s -> Decimal p s
$cnegate :: forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
* :: Decimal p s -> Decimal p s -> Decimal p s
$c* :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
- :: Decimal p s -> Decimal p s -> Decimal p s
$c- :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
+ :: Decimal p s -> Decimal p s -> Decimal p s
$c+ :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
Num, Rational -> Decimal p s
Decimal p s -> Decimal p s
Decimal p s -> Decimal p s -> Decimal p s
forall (p :: Natural) (s :: Natural). Num (Decimal p s)
forall (p :: Natural) (s :: Natural). Rational -> Decimal p s
forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
forall a.
Num a
-> (a -> a -> a) -> (a -> a) -> (Rational -> a) -> Fractional a
fromRational :: Rational -> Decimal p s
$cfromRational :: forall (p :: Natural) (s :: Natural). Rational -> Decimal p s
recip :: Decimal p s -> Decimal p s
$crecip :: forall (p :: Natural) (s :: Natural). Decimal p s -> Decimal p s
/ :: Decimal p s -> Decimal p s -> Decimal p s
$c/ :: forall (p :: Natural) (s :: Natural).
Decimal p s -> Decimal p s -> Decimal p s
Fractional, Decimal p s -> Rational
forall (p :: Natural) (s :: Natural). Num (Decimal p s)
forall (p :: Natural) (s :: Natural). Ord (Decimal p s)
forall (p :: Natural) (s :: Natural). Decimal p s -> Rational
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
toRational :: Decimal p s -> Rational
$ctoRational :: forall (p :: Natural) (s :: Natural). Decimal p s -> Rational
Real)

intScale :: D.BigDecimal -> Integer
intScale :: BigDecimal -> Integer
intScale = forall a. Integral a => a -> Integer
toInteger forall b c a. (b -> c) -> (a -> b) -> a -> c
. BigDecimal -> Natural
D.scale

fromUnderlyingValue
  :: forall p s. KnownNat s
  => Integer -> Decimal p s
fromUnderlyingValue :: forall (p :: Natural) (s :: Natural).
KnownNat s =>
Integer -> Decimal p s
fromUnderlyingValue Integer
n
  = forall (p :: Natural) (s :: Natural). BigDecimal -> Decimal p s
Decimal forall a b. (a -> b) -> a -> b
$ Integer -> Natural -> BigDecimal
D.BigDecimal Integer
n (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall (n :: Natural) (proxy :: Natural -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s))

underlyingValue
  :: forall s p. (KnownNat p, KnownNat s)
  => Decimal p s -> Maybe Int
underlyingValue :: forall (s :: Natural) (p :: Natural).
(KnownNat p, KnownNat s) =>
Decimal p s -> Maybe Int
underlyingValue (Decimal BigDecimal
d)
  = let ss :: Integer
ss = forall (n :: Natural) (proxy :: Natural -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s)
        pp :: Integer
pp = forall (n :: Natural) (proxy :: Natural -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy p)
        new :: BigDecimal
new = if Integer
ss forall a. Ord a => a -> a -> Bool
> BigDecimal -> Integer
intScale BigDecimal
d
                 then Integer -> Natural -> BigDecimal
D.BigDecimal (BigDecimal -> Integer
D.value BigDecimal
d forall a. Num a => a -> a -> a
* Integer
10 forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
ss forall a. Num a => a -> a -> a
- BigDecimal -> Integer
intScale BigDecimal
d)) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
ss)
                 else BigDecimal -> RoundingAdvice -> BigDecimal
D.roundBD BigDecimal
d (Natural -> RoundingAdvice
D.halfUp (forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
ss))
    in if BigDecimal -> Natural
D.precision BigDecimal
new forall a. Ord a => a -> a -> Bool
> forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
pp
          then forall a. Maybe a
Nothing
          else forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Num a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ BigDecimal -> Integer
D.value BigDecimal
new