{- |
Module                  : Toml.Codec.Combinator.Tuple
Copyright               : (c) 2018-2021 Kowainik
SPDX-License-Identifier : MPL-2.0
Maintainer              : Kowainik <xrom.xkov@gmail.com>
Stability               : Stable
Portability             : Portable

TOML-specific combinators for converting between TOML and Haskell tuples.
It's recommended to create your custom data types and implement codecs
for them, but if you need to have tuples (e.g. for decoding different
constructors of sum types), you can find codecs from this module
helpful.

+-------------------------------+---------------+------------------------+
|         Haskell Type          |    @TOML@     |   'TomlCodec'          |
+===============================+===============+========================+
| __@('Int', 'Text')@__         | @[foo]@       | @'pair'@               |
+-------------------------------+---------------+------------------------+
|                               | @    a = 42@  | @    ('Toml.int' "a")@ |
+-------------------------------+---------------+------------------------+
|                               |@    b = "bar"@| @    ('Toml.text' "b")@|
+-------------------------------+---------------+------------------------+
| __@('Int', 'Text', 'Bool')@__ | @[foo]@       | @'triple'@             |
+-------------------------------+---------------+------------------------+
|                               | @    a = 42@  | @    ('Toml.int' "a")@ |
+-------------------------------+---------------+------------------------+
|                               |@    b = "bar"@| @    ('Toml.text' "b")@|
+-------------------------------+---------------+------------------------+
|                               |@    c = false@| @    ('Toml.bool' "c")@|
+-------------------------------+---------------+------------------------+

@since 1.3.0.0
-}

module Toml.Codec.Combinator.Tuple
    ( pair
    , triple
    ) where

import Toml.Codec.Di ((.=))
import Toml.Codec.Types (TomlCodec)


{- | Codec for pair of values. Takes codecs for the first and for the second
values of the pair.

If I have the following @TOML@ entry

@
myPair = { first = 11, second = "eleven"}
@

and want to convert it into the Haskell tuple of two elements, I can use the
following codec:

@
myPairCodec :: 'TomlCodec' ('Int', 'Text')
myPairCodec = flip Toml.'table' \"myPair\" $ Toml.'pair'
    (Toml.'int' \"first\")
    (Toml.'text' \"second\")
@

@since 1.3.0.0
-}
pair :: TomlCodec a -> TomlCodec b -> TomlCodec (a, b)
pair :: forall a b. TomlCodec a -> TomlCodec b -> TomlCodec (a, b)
pair TomlCodec a
aCodec TomlCodec b
bCodec = (,)
    (a -> b -> (a, b)) -> Codec (a, b) a -> Codec (a, b) (b -> (a, b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TomlCodec a
aCodec TomlCodec a -> ((a, b) -> a) -> Codec (a, b) a
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= (a, b) -> a
forall a b. (a, b) -> a
fst
    Codec (a, b) (b -> (a, b)) -> Codec (a, b) b -> Codec (a, b) (a, b)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TomlCodec b
bCodec TomlCodec b -> ((a, b) -> b) -> Codec (a, b) b
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= (a, b) -> b
forall a b. (a, b) -> b
snd
{-# INLINE pair #-}

{- | Codec for triple of values. Takes codecs for the first, second and third
values of the triple.

If I have the following @TOML@ entry

@
myTriple =
    { first = 11
    , second = "eleven"
    , isMyFavourite = true
    }
@

and want to convert it into the Haskell tuple of three elements, I can use the
following codec:

@
myTripleCodec :: 'TomlCodec' ('Int', 'Text', 'Bool')
myTripleCodec = flip Toml.'table' \"myTriple\" $ Toml.'triple'
    (Toml.'int' \"first\")
    (Toml.'text' \"second\")
    (Toml.'bool' \"isMyFavourite\")
@

@since 1.3.0.0
-}
triple :: TomlCodec a -> TomlCodec b -> TomlCodec c -> TomlCodec (a, b, c)
triple :: forall a b c.
TomlCodec a -> TomlCodec b -> TomlCodec c -> TomlCodec (a, b, c)
triple TomlCodec a
aCodec TomlCodec b
bCodec TomlCodec c
cCodec = (,,)
    (a -> b -> c -> (a, b, c))
-> Codec (a, b, c) a -> Codec (a, b, c) (b -> c -> (a, b, c))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TomlCodec a
aCodec TomlCodec a -> ((a, b, c) -> a) -> Codec (a, b, c) a
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= (\(a
a, b
_, c
_) -> a
a)
    Codec (a, b, c) (b -> c -> (a, b, c))
-> Codec (a, b, c) b -> Codec (a, b, c) (c -> (a, b, c))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TomlCodec b
bCodec TomlCodec b -> ((a, b, c) -> b) -> Codec (a, b, c) b
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= (\(a
_, b
b, c
_) -> b
b)
    Codec (a, b, c) (c -> (a, b, c))
-> Codec (a, b, c) c -> Codec (a, b, c) (a, b, c)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TomlCodec c
cCodec TomlCodec c -> ((a, b, c) -> c) -> Codec (a, b, c) c
forall field a object.
Codec field a -> (object -> field) -> Codec object a
.= (\(a
_, b
_, c
c) -> c
c)
{-# INLINE triple #-}