module Data.Aeson.Types.Internal
(
Value(..)
, Array
, emptyArray, isEmptyArray
, Pair
, Object
, emptyObject
, Parser
, Result(..)
, parse
, parseEither
, parseMaybe
, modifyFailure
, object
, Options(..)
, SumEncoding(..)
, defaultOptions
, defaultTaggedObject
) where
import Control.Applicative
import Control.Monad
import Control.DeepSeq (NFData(..))
import Data.Attoparsec.Char8 (Number(..))
import Data.Hashable (Hashable(..))
import Data.HashMap.Strict (HashMap)
import Data.Monoid (Monoid(..))
import Data.String (IsString(..))
import Data.Text (Text, pack)
import Data.Typeable (Typeable)
import Data.Vector (Vector)
import qualified Data.HashMap.Strict as H
import qualified Data.Vector as V
data Result a = Error String
| Success a
deriving (Eq, Show, Typeable)
instance (NFData a) => NFData (Result a) where
rnf (Success a) = rnf a
rnf (Error err) = rnf err
instance Functor Result where
fmap f (Success a) = Success (f a)
fmap _ (Error err) = Error err
instance Monad Result where
return = Success
Success a >>= k = k a
Error err >>= _ = Error err
instance Applicative Result where
pure = return
(<*>) = ap
instance MonadPlus Result where
mzero = fail "mzero"
mplus a@(Success _) _ = a
mplus _ b = b
instance Alternative Result where
empty = mzero
(<|>) = mplus
instance Monoid (Result a) where
mempty = fail "mempty"
mappend = mplus
type Failure f r = String -> f r
type Success a f r = a -> f r
newtype Parser a = Parser {
runParser :: forall f r.
Failure f r
-> Success a f r
-> f r
}
instance Monad Parser where
m >>= g = Parser $ \kf ks -> let ks' a = runParser (g a) kf ks
in runParser m kf ks'
return a = Parser $ \_kf ks -> ks a
fail msg = Parser $ \kf _ks -> kf msg
instance Functor Parser where
fmap f m = Parser $ \kf ks -> let ks' a = ks (f a)
in runParser m kf ks'
instance Applicative Parser where
pure = return
(<*>) = apP
instance Alternative Parser where
empty = fail "empty"
(<|>) = mplus
instance MonadPlus Parser where
mzero = fail "mzero"
mplus a b = Parser $ \kf ks -> let kf' _ = runParser b kf ks
in runParser a kf' ks
instance Monoid (Parser a) where
mempty = fail "mempty"
mappend = mplus
apP :: Parser (a -> b) -> Parser a -> Parser b
apP d e = do
b <- d
a <- e
return (b a)
type Object = HashMap Text Value
type Array = Vector Value
data Value = Object !Object
| Array !Array
| String !Text
| Number !Number
| Bool !Bool
| Null
deriving (Eq, Show, Typeable)
instance NFData Value where
rnf (Object o) = rnf o
rnf (Array a) = V.foldl' (\x y -> rnf y `seq` x) () a
rnf (String s) = rnf s
rnf (Number n) = case n of I i -> rnf i; D d -> rnf d
rnf (Bool b) = rnf b
rnf Null = ()
instance IsString Value where
fromString = String . pack
instance Hashable Value where
hashWithSalt s (Object o) = H.foldl' hashWithSalt
(s `hashWithSalt` (0::Int)) o
hashWithSalt s (Array a) = V.foldl' hashWithSalt
(s `hashWithSalt` (1::Int)) a
hashWithSalt s (String str) = s `hashWithSalt` (2::Int) `hashWithSalt` str
hashWithSalt s (Number n) = 3 `hashWithSalt`
case n of I i -> hashWithSalt s i
D d -> hashWithSalt s d
hashWithSalt s (Bool b) = s `hashWithSalt` (4::Int) `hashWithSalt` b
hashWithSalt s Null = s `hashWithSalt` (5::Int)
emptyArray :: Value
emptyArray = Array V.empty
isEmptyArray :: Value -> Bool
isEmptyArray (Array arr) = V.null arr
isEmptyArray _ = False
emptyObject :: Value
emptyObject = Object H.empty
parse :: (a -> Parser b) -> a -> Result b
parse m v = runParser (m v) Error Success
parseMaybe :: (a -> Parser b) -> a -> Maybe b
parseMaybe m v = runParser (m v) (const Nothing) Just
parseEither :: (a -> Parser b) -> a -> Either String b
parseEither m v = runParser (m v) Left Right
type Pair = (Text, Value)
object :: [Pair] -> Value
object = Object . H.fromList
modifyFailure :: (String -> String) -> Parser a -> Parser a
modifyFailure f (Parser p) = Parser $ \kf -> p (kf . f)
data Options = Options
{ fieldLabelModifier :: String -> String
, constructorTagModifier :: String -> String
, allNullaryToStringTag :: Bool
, omitNothingFields :: Bool
, sumEncoding :: SumEncoding
}
data SumEncoding =
TaggedObject { tagFieldName :: String
, contentsFieldName :: String
}
| ObjectWithSingleField
| TwoElemArray
defaultOptions :: Options
defaultOptions = Options
{ fieldLabelModifier = id
, constructorTagModifier = id
, allNullaryToStringTag = True
, omitNothingFields = False
, sumEncoding = defaultTaggedObject
}
defaultTaggedObject :: SumEncoding
defaultTaggedObject = TaggedObject
{ tagFieldName = "tag"
, contentsFieldName = "contents"
}