{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE ScopedTypeVariables        #-}
module Data.Avro.Schema.Decimal where

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

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

fromUnderlyingValue
  :: forall p s. KnownNat s
  => Integer -> Decimal p s
fromUnderlyingValue :: Integer -> Decimal p s
fromUnderlyingValue Integer
n
  = BigDecimal -> Decimal p s
forall (p :: Nat) (s :: Nat). BigDecimal -> Decimal p s
Decimal (BigDecimal -> Decimal p s) -> BigDecimal -> Decimal p s
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> BigDecimal
D.BigDecimal Integer
n (Proxy s -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy s
forall k (t :: k). Proxy t
Proxy :: Proxy s))

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