{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE CPP #-}
-- |
--
-- Builder functions for 'CommaSeparated' values.
--
module Waargonaut.Encode.Builder.CommaSep (commaSeparatedBuilder) where

#if !MIN_VERSION_base(4,11,0)
import           Data.Monoid                     ((<>))
#endif

import           Waargonaut.Types.CommaSep       (Comma, CommaSeparated (..),
                                                  Elem (..), Elems (..))

import           Waargonaut.Encode.Builder.Types (Builder (..))

-- | Builder for UTF8 Comma
commaBuilder :: Builder t b -> b
commaBuilder :: Builder t b -> b
commaBuilder Builder t b
b = Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
b Char
','
{-# INLINE commaBuilder #-}

-- | Builder for a comma and trailing whitespace combination.
commaTrailingBuilder
  :: ( Monoid b
     , Foldable f
     )
  => Builder t b
  -> (Builder t b -> ws -> b)
  -> f (Comma, ws)
  -> b
commaTrailingBuilder :: Builder t b -> (Builder t b -> ws -> b) -> f (Comma, ws) -> b
commaTrailingBuilder Builder t b
bldr Builder t b -> ws -> b
wsB =
  ((Comma, ws) -> b) -> f (Comma, ws) -> b
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ((Builder t b -> b
forall t b. Builder t b -> b
commaBuilder Builder t b
bldr b -> b -> b
forall a. Semigroup a => a -> a -> a
<>) (b -> b) -> ((Comma, ws) -> b) -> (Comma, ws) -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder t b -> ws -> b
wsB Builder t b
bldr) (ws -> b) -> ((Comma, ws) -> ws) -> (Comma, ws) -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Comma, ws) -> ws
forall a b. (a, b) -> b
snd)

-- | Using the given builders for the whitespace and elements (@a@), create a
-- builder for a 'CommaSeparated'.
commaSeparatedBuilder
  :: forall ws a t b. Monoid b
  => Builder t b
  -> Char
  -> Char
  -> (Builder t b -> ws -> b)
  -> (Builder t b -> a -> b)
  -> CommaSeparated ws a
  -> b
commaSeparatedBuilder :: Builder t b
-> Char
-> Char
-> (Builder t b -> ws -> b)
-> (Builder t b -> a -> b)
-> CommaSeparated ws a
-> b
commaSeparatedBuilder Builder t b
bldr Char
op Char
fin Builder t b -> ws -> b
wsB Builder t b -> a -> b
aB (CommaSeparated ws
lws Maybe (Elems ws a)
sepElems) =
  Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
op b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Builder t b -> ws -> b
wsB Builder t b
bldr ws
lws b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b -> (Elems ws a -> b) -> Maybe (Elems ws a) -> b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe b
forall a. Monoid a => a
mempty Elems ws a -> b
buildElems Maybe (Elems ws a)
sepElems b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
fin
  where
    elemBuilder :: Elem f ws a -> b
elemBuilder (Elem a
e f (Comma, ws)
eTrailing) =
      Builder t b -> a -> b
aB Builder t b
bldr a
e b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Builder t b -> (Builder t b -> ws -> b) -> f (Comma, ws) -> b
forall b (f :: * -> *) t ws.
(Monoid b, Foldable f) =>
Builder t b -> (Builder t b -> ws -> b) -> f (Comma, ws) -> b
commaTrailingBuilder Builder t b
bldr Builder t b -> ws -> b
wsB f (Comma, ws)
eTrailing

    buildElems :: Elems ws a -> b
buildElems (Elems Vector (Elem Identity ws a)
es Elem Maybe ws a
elst) =
      (Elem Identity ws a -> b) -> Vector (Elem Identity ws a) -> b
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap Elem Identity ws a -> b
forall (f :: * -> *). Foldable f => Elem f ws a -> b
elemBuilder Vector (Elem Identity ws a)
es b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Elem Maybe ws a -> b
forall (f :: * -> *). Foldable f => Elem f ws a -> b
elemBuilder Elem Maybe ws a
elst