{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Money.Xmlbf () where
import Control.Applicative (empty)
import Control.Monad (when)
import Data.Ratio ((%), numerator, denominator)
import qualified Data.Text as T
import GHC.Exts (fromList)
import GHC.TypeLits (KnownSymbol)
import qualified Money
import qualified Xmlbf
import qualified Data.Text.Read as TR
pRead :: Integral a => TR.Reader a -> T.Text -> Xmlbf.Parser a
{-# INLINE pRead #-}
pRead rdr txt = case rdr txt of
Right (a, "") -> pure a
Right _ -> fail "Money.Xmblbf.pRead: did not match fully."
Left err -> fail err
instance KnownSymbol currency => Xmlbf.ToXml (Money.Dense currency) where
toXml = Xmlbf.toXml . Money.toSomeDense
instance KnownSymbol currency => Xmlbf.FromXml (Money.Dense currency) where
fromXml = maybe empty pure =<< fmap Money.fromSomeDense Xmlbf.fromXml
instance Xmlbf.ToXml Money.SomeDense where
toXml = \sd ->
let r = Money.someDenseAmount sd
as = [ (T.pack "c", Money.someDenseCurrency sd)
, (T.pack "n", T.pack (show (numerator r)))
, (T.pack "d", T.pack (show (denominator r))) ]
in [ either error id (Xmlbf.element' "money-dense" (fromList as) []) ]
instance Xmlbf.FromXml Money.SomeDense where
fromXml = Xmlbf.pElement (T.pack "money-dense") $ do
c <- Xmlbf.pAttr "c"
n <- pRead (TR.signed TR.decimal) =<< Xmlbf.pAttr "n"
d <- pRead TR.decimal =<< Xmlbf.pAttr "d"
when (d == 0) (fail "denominator is zero")
maybe empty pure (Money.mkSomeDense c (n % d))
instance
( KnownSymbol currency, Money.GoodScale scale
) => Xmlbf.ToXml (Money.Discrete' currency scale) where
toXml = Xmlbf.toXml . Money.toSomeDiscrete
instance
( KnownSymbol currency, Money.GoodScale scale
) => Xmlbf.FromXml (Money.Discrete' currency scale) where
fromXml = maybe empty pure =<< fmap Money.fromSomeDiscrete Xmlbf.fromXml
instance Xmlbf.ToXml Money.SomeDiscrete where
toXml = \sd ->
let r = Money.scaleToRational (Money.someDiscreteScale sd)
as = [ ("c", Money.someDiscreteCurrency sd)
, ("n", T.pack (show (numerator r)))
, ("d", T.pack (show (denominator r)))
, ("a", T.pack (show (Money.someDiscreteAmount sd))) ]
in [ either error id (Xmlbf.element' "money-discrete" (fromList as) []) ]
instance Xmlbf.FromXml Money.SomeDiscrete where
fromXml = Xmlbf.pElement (T.pack "money-discrete") $ do
c <- Xmlbf.pAttr "c"
n <- pRead TR.decimal =<< Xmlbf.pAttr "n"
d <- pRead TR.decimal =<< Xmlbf.pAttr "d"
when (d == 0) (fail "denominator is zero")
a <- pRead (TR.signed TR.decimal) =<< Xmlbf.pAttr "a"
maybe empty pure (Money.mkSomeDiscrete c <$> Money.scaleFromRational (n % d)
<*> pure a)
instance
( KnownSymbol src, KnownSymbol dst
) => Xmlbf.ToXml (Money.ExchangeRate src dst) where
toXml = Xmlbf.toXml . Money.toSomeExchangeRate
instance
( KnownSymbol src, KnownSymbol dst
) => Xmlbf.FromXml (Money.ExchangeRate src dst) where
fromXml = maybe empty pure =<< fmap Money.fromSomeExchangeRate Xmlbf.fromXml
instance Xmlbf.ToXml Money.SomeExchangeRate where
toXml = \ser ->
let r = Money.someExchangeRateRate ser
as = [ ("src", Money.someExchangeRateSrcCurrency ser)
, ("dst", Money.someExchangeRateDstCurrency ser)
, ("n", T.pack (show (numerator r)))
, ("d", T.pack (show (denominator r))) ]
in [ either error id (Xmlbf.element' "exchange-rate" (fromList as) []) ]
instance Xmlbf.FromXml Money.SomeExchangeRate where
fromXml = Xmlbf.pElement (T.pack "exchange-rate") $ do
src <- Xmlbf.pAttr "src"
dst <- Xmlbf.pAttr "dst"
n <- pRead TR.decimal =<< Xmlbf.pAttr "n"
d <- pRead TR.decimal =<< Xmlbf.pAttr "d"
when (d == 0) (fail "denominator is zero")
maybe empty pure (Money.mkSomeExchangeRate src dst (n % d))