waargonaut-0.8.0.0: src/Waargonaut/Types/JArray.hs
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
-- |
--
-- JSON Array representation and functions.
--
module Waargonaut.Types.JArray
(
-- * Types
JArray (..)
-- * Parser
, parseJArray
) where
import Prelude (Eq, Show, Int)
import Control.Category ((.))
import Control.Error.Util (note)
import Control.Lens (AsEmpty (..), Cons (..), Rewrapped, Ixed (..), Index, IxValue,
Wrapped (..), cons, iso,
nearly, over, prism, to, ( # ),
(^.), (^?), _2, _Wrapped)
import Control.Lens.Extras (is)
import Control.Monad (Monad)
import Data.Bifoldable (Bifoldable (bifoldMap))
import Data.Bifunctor (Bifunctor (bimap))
import Data.Bitraversable (Bitraversable (bitraverse))
import Data.Foldable (Foldable)
import Data.Function (($))
import Data.Functor (Functor, (<$>))
import Data.Monoid (Monoid (..), mempty)
import Data.Semigroup (Semigroup (..))
import Data.Traversable (Traversable)
import Text.Parser.Char (CharParsing, char)
import Waargonaut.Types.CommaSep (CommaSeparated,
parseCommaSeparated)
-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Utils
-- >>> import Waargonaut.Types.Json
-- >>> import Waargonaut.Types.Whitespace
-- >>> import Control.Monad (return)
-- >>> import Data.Either (Either (..), isLeft)
-- >>> import Waargonaut.Decode.Error (DecodeError)
----
-- | Conveniently, a JSON array is a 'CommaSeparated' list with an optional
-- trailing comma, some instances and other functions need to work differently so
-- we wrap it up in a newtype.
newtype JArray ws a =
JArray (CommaSeparated ws a)
deriving (Eq, Show, Functor, Foldable, Traversable)
instance JArray ws a ~ t => Rewrapped (JArray ws a) t
instance Wrapped (JArray ws a) where
type Unwrapped (JArray ws a) = CommaSeparated ws a
_Wrapped' = iso (\(JArray x) -> x) JArray
instance Monoid ws => Cons (JArray ws a) (JArray ws a) a a where
_Cons = prism
(\(a,j) -> over _Wrapped (cons a) j)
(\j -> note j $ over _2 (_Wrapped #) <$> j ^? _Wrapped . _Cons)
{-# INLINE _Cons #-}
instance (Semigroup ws, Monoid ws) => AsEmpty (JArray ws a) where
_Empty = nearly (JArray mempty) (^. _Wrapped . to (is _Empty))
{-# INLINE _Empty #-}
instance (Monoid ws, Semigroup ws) => Semigroup (JArray ws a) where
(JArray a) <> (JArray b) = JArray (a <> b)
instance (Semigroup ws, Monoid ws) => Monoid (JArray ws a) where
mempty = JArray mempty
mappend = (<>)
type instance IxValue (JArray ws a) = a
type instance Index (JArray ws a) = Int
instance Ixed (JArray ws a) where
ix i f (JArray cs) = JArray <$> ix i f cs
instance Bifunctor JArray where
bimap f g (JArray cs) = JArray (bimap f g cs)
instance Bifoldable JArray where
bifoldMap f g (JArray cs) = bifoldMap f g cs
instance Bitraversable JArray where
bitraverse f g (JArray cs) = JArray <$> bitraverse f g cs
-- | Parse a single JSON array
--
-- >>> testparse (parseJArray parseWhitespace parseWaargonaut) "[null ]"
-- Right (JArray (CommaSeparated (WS []) (Just (Elems {_elemsElems = [], _elemsLast = Elem {_elemVal = Json (JNull (WS [Space])), _elemTrailing = Nothing}}))))
--
-- >>> testparse (parseJArray parseWhitespace parseWaargonaut) "[null,]"
-- Right (JArray (CommaSeparated (WS []) (Just (Elems {_elemsElems = [], _elemsLast = Elem {_elemVal = Json (JNull (WS [])), _elemTrailing = Just (Comma,WS [])}}))))
--
parseJArray
:: ( Monad f
, CharParsing f
)
=> f ws
-> f a
-> f (JArray ws a)
parseJArray ws a = JArray <$>
parseCommaSeparated (char '[') (char ']') ws a