{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} module JSON where import Data.Aeson.Types import qualified Data.HashMap.Strict as M import Data.Text (Text) import Data.Vector (Vector) import qualified Data.Vector as V import Text.Toml.Types -- * Regular ToJSON instances -- | 'ToJSON' instances for the 'Node' type that produce Aeson (JSON) -- in line with the TOML specification. instance ToJSON Node where toJSON (VTable v) = toJSON v toJSON (VTArray v) = toJSON v toJSON (VString v) = toJSON v toJSON (VInteger v) = toJSON v toJSON (VFloat v) = toJSON v toJSON (VBoolean v) = toJSON v toJSON (VDatetime v) = toJSON v toJSON (VArray v) = toJSON v -- * Special BurntSushi ToJSON type class and instances -- | Type class for conversion to BurntSushi-style JSON. -- -- BurntSushi has made a language agnostic test suite available that -- this library uses. This test suite expects that values are encoded -- as JSON objects with a 'type' and a 'value' member. class ToBsJSON a where toBsJSON :: a -> Value -- | Provide a 'toBsJSON' instance to the 'VTArray'. instance (ToBsJSON a) => ToBsJSON (Vector a) where toBsJSON = Array . V.map toBsJSON {-# INLINE toBsJSON #-} -- | Provide a 'toBsJSON' instance to the 'NTable'. instance (ToBsJSON v) => ToBsJSON (M.HashMap Text v) where toBsJSON = Object . M.map toBsJSON {-# INLINE toBsJSON #-} -- | 'ToBsJSON' instances for the 'TValue' type that produce Aeson (JSON) -- in line with BurntSushi's language agnostic TOML test suite. -- -- As seen in this function, BurntSushi's JSON encoding explicitly -- specifies the types of the values. instance ToBsJSON Node where toBsJSON (VTable v) = toBsJSON v toBsJSON (VTArray v) = toBsJSON v toBsJSON (VString v) = object [ "type" .= toJSON ("string" :: String) , "value" .= toJSON v ] toBsJSON (VInteger v) = object [ "type" .= toJSON ("integer" :: String) , "value" .= toJSON (show v) ] toBsJSON (VFloat v) = object [ "type" .= toJSON ("float" :: String) , "value" .= toJSON (show v) ] toBsJSON (VBoolean v) = object [ "type" .= toJSON ("bool" :: String) , "value" .= toJSON (if v then "true" else "false" :: String) ] toBsJSON (VDatetime v) = object [ "type" .= toJSON ("datetime" :: String) , "value" .= toJSON (let s = show v z = take (length s - 4) s ++ "Z" d = take (length z - 10) z t = drop (length z - 9) z in d ++ "T" ++ t) ] toBsJSON (VArray v) = object [ "type" .= toJSON ("array" :: String) , "value" .= toBsJSON v ]