Skip to content

Commit

Permalink
Functions for Encoding JSON Values
Browse files Browse the repository at this point in the history
  • Loading branch information
vijayphoenix committed Jul 18, 2019
1 parent 68d1841 commit 63e7ce9
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Revision history for HsYAML-aeson

## 0.2.0.0

* Changes in accordance with HsYAML-0.2.0.0 (#1)
* New convinence function `decode1Strict`
* New functions`encode1`, `encode1Strict`, `encodeValue`, `encodeValue'` for encoding JSON Values

## 0.1.0.0

* First release. Released on an unsuspecting world.
5 changes: 4 additions & 1 deletion HsYAML-aeson.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.2
name: HsYAML-aeson
version: 0.1.0.0
version: 0.2.0.0
license: GPL-2.0-or-later
license-file: LICENSE.GPLv2
author: Herbert Valerio Riedel
Expand Down Expand Up @@ -34,8 +34,11 @@ library
, aeson ^>= 1.4.0.0
, base >= 4.5 && < 4.13
, bytestring ^>= 0.9.2.1 || ^>= 0.10.0.2
, containers >=0.4.2 && <0.7
, mtl ^>= 2.2.1
, scientific ^>= 0.3.6.2
, text ^>= 1.2.3.1
, unordered-containers >= 0.2 && < 0.3
, vector ^>= 0.12.0.2

hs-source-dirs: src
Expand Down
8 changes: 8 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
packages: .

source-repository-package
type: git
location: https://github.com/hvr/HsYAML.git

package HsYAML-aeson
flags: +exe
77 changes: 75 additions & 2 deletions src/Data/YAML/Aeson.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE Trustworthy #-}

Expand All @@ -19,23 +20,34 @@
module Data.YAML.Aeson
( -- * Parsing YAML using JSON models
-- ** High-level parsing/decoding via 'FromJSON' instances
Data.YAML.Aeson.decode1
decode1
, decode1'
, decode1Strict
-- ** Parsing into JSON AST ('J.Value')
, decodeValue
, decodeValue'
, scalarToValue
-- ** Encoding/Dumping
, encode1
, encode1Strict
, encodeValue
, encodeValue'
) where

import Control.Applicative as Ap
import Control.Monad.Identity (runIdentity)
import Data.Aeson as J
import qualified Data.Aeson.Types as J
import qualified Data.ByteString.Lazy as BS.L
import qualified Data.ByteString as BS
import Data.Text (Text)
import qualified Data.Vector as V
import Data.YAML as Y
import Data.YAML as Y hiding (decode1, decode1Strict, encode1, encode1Strict)
import Data.YAML.Event (Pos)
import qualified Data.YAML.Token as YT
import Data.Scientific
import qualified Data.Map as Map
import qualified Data.HashMap.Strict as HM

-- | Parse a single YAML document using the 'coreSchemaResolver' and decode to Haskell types using 'FromJSON' instances.
--
Expand All @@ -57,6 +69,12 @@ decode1 bs = case decodeValue bs of
J.Success v2 -> Right $! v2
J.Error err -> Left ("fromJSON: " ++ err)

-- | Like 'decode1' but takes a strict 'BS.ByteString'
--
-- @since 0.2.0
decode1Strict :: FromJSON v => BS.ByteString -> Either String v
decode1Strict = decode1 . BS.L.fromChunks . (:[])

-- | Variant of 'decode1' allowing for customization. See 'decodeValue'' for documentation of parameters.
decode1' :: FromJSON v => SchemaResolver -> (J.Value -> Either String Text) -> BS.L.ByteString -> Either String v
decode1' schema keyconv bs = case decodeValue' schema keyconv bs of
Expand Down Expand Up @@ -142,3 +160,58 @@ scalarToValue (Y.SFloat x) = Just $! J.Number (realToFrac x)
scalarToValue (Y.SInt i) = Just $! J.Number (fromInteger i)
scalarToValue (SStr t) = Just $! J.String t
scalarToValue (SUnknown _ _) = Nothing


-- | Equivalent to the fuction Data.ByteString.toStrict.
-- O(n) Convert a lazy ByteString into a strict ByteString.
{-# INLINE bsToStrict #-}
bsToStrict :: BS.L.ByteString -> BS.ByteString
#if MIN_VERSION_bytestring(0,10,0)
bsToStrict = BS.L.toStrict
#else
bsToStrict = BS.concat . BS.L.toChunks
#endif

-- | @since 0.2.0
instance ToYAML J.Value where
toYAML J.Null = Scalar () SNull
toYAML (J.Bool b) = toYAML b
toYAML (J.String txt) = toYAML txt
toYAML (J.Number sc) = case floatingOrInteger sc :: Either Double Integer of
Right d -> toYAML d
Left int -> toYAML int
toYAML (J.Array a) = toYAML (V.toList a)
toYAML (J.Object o) = toYAML (Map.fromList (HM.toList o))

-- | Serialize JSON Value using the YAML 1.2 Core schema to a lazy 'BS.L.ByteString'.
--
-- 'encode1' emits exactly one YAML document.
--
-- See 'encodeValue' for more information about this functions' YAML
-- encoder configuration.
--
-- @since 0.2.0
encode1 :: ToJSON v => v -> BS.L.ByteString
encode1 a = encodeValue [J.toJSON a]

-- | Like 'encode1' but outputs 'BS.ByteString'
--
-- @since 0.2.0
encode1Strict :: ToJSON v => v -> BS.ByteString
encode1Strict = bsToStrict . encode1

-- | Dump YAML Nodes as a lazy 'BS.L.ByteString'
--
-- Each YAML 'Node' is emitted as a individual YAML Document where each Document is terminated by a 'DocumentEnd' indicator.
--
-- This is a convenience wrapper over `encodeNode'`
--
-- @since 0.2.0
encodeValue :: [J.Value] -> BS.L.ByteString
encodeValue = encodeValue' coreSchemaEncoder YT.UTF8

-- | Customizable variant of 'encodeNode'
--
-- @since 0.2.0
encodeValue' :: SchemaEncoder -> YT.Encoding -> [J.Value] -> BS.L.ByteString
encodeValue' schemaEncoder encoding values = Y.encodeNode' schemaEncoder encoding (map (Doc. toYAML) values)

0 comments on commit 63e7ce9

Please sign in to comment.