{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Money.Serialise () where
import qualified Codec.Serialise as Ser
import Control.Monad (when)
import Data.Ratio ((%), numerator, denominator)
import GHC.TypeLits (KnownSymbol)
import qualified Money
import qualified Money.Internal as MoneyI
instance (KnownSymbol currency) => Ser.Serialise (Money.Dense currency) where
encode = Ser.encode . Money.toSomeDense
decode = maybe (fail "Dense") pure =<< fmap Money.fromSomeDense Ser.decode
instance
( KnownSymbol currency, Money.GoodScale scale
) => Ser.Serialise (Money.Discrete' currency scale) where
encode = Ser.encode . Money.toSomeDiscrete
decode = maybe (fail "Discrete'") pure
=<< fmap Money.fromSomeDiscrete Ser.decode
instance
( KnownSymbol src, KnownSymbol dst
) => Ser.Serialise (Money.ExchangeRate src dst) where
encode = Ser.encode . Money.toSomeExchangeRate
decode = maybe (fail "ExchangeRate") pure
=<< fmap Money.fromSomeExchangeRate Ser.decode
instance Ser.Serialise Money.Scale where
encode = \s ->
let r = Money.scaleToRational s
in Ser.encode (numerator r) <>
Ser.encode (denominator r)
decode = maybe (fail "Scale") pure =<< do
n :: Integer <- Ser.decode
d :: Integer <- Ser.decode
when (d == 0) (fail "denominator is zero")
pure (MoneyI.scaleFromRational (n % d))
instance Ser.Serialise Money.SomeDense where
encode = \sd ->
let r = Money.someDenseAmount sd
in Ser.encode (MoneyI.someDenseCurrency' sd) <>
Ser.encode (numerator r) <>
Ser.encode (denominator r)
decode = maybe (fail "SomeDense") pure =<< do
c :: String <- Ser.decode
n :: Integer <- Ser.decode
d :: Integer <- Ser.decode
when (d == 0) (fail "denominator is zero")
pure (MoneyI.mkSomeDense' c (n % d))
instance Ser.Serialise Money.SomeDiscrete where
encode = \sd ->
Ser.encode (MoneyI.someDiscreteCurrency' sd) <>
Ser.encode (Money.someDiscreteScale sd) <>
Ser.encode (Money.someDiscreteAmount sd)
decode = do
c :: String <- Ser.decode
s :: Money.Scale <- Ser.decode
a :: Integer <- Ser.decode
pure (MoneyI.mkSomeDiscrete' c s a)
instance Ser.Serialise Money.SomeExchangeRate where
encode = \ser ->
let r = Money.someExchangeRateRate ser
in Ser.encode (MoneyI.someExchangeRateSrcCurrency' ser) <>
Ser.encode (MoneyI.someExchangeRateDstCurrency' ser) <>
Ser.encode (numerator r) <>
Ser.encode (denominator r)
decode = maybe (fail "SomeExchangeRate") pure =<< do
src :: String <- Ser.decode
dst :: String <- Ser.decode
n :: Integer <- Ser.decode
d :: Integer <- Ser.decode
when (d == 0) (fail "denominator is zero")
pure (MoneyI.mkSomeExchangeRate' src dst (n % d))