packages feed

json-builder 0.0.1 → 0.1.0

raw patch · 3 files changed

+173/−98 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Json.Builder: Escaped :: Builder -> Escaped
- Data.Json.Builder: class Value a => Key a
- Data.Json.Builder: instance [incoherent] (Key k, Value a) => Value (HashMap k a)
- Data.Json.Builder: instance [incoherent] (Key k, Value a) => Value (Map k a)
- Data.Json.Builder: instance [incoherent] Key ByteString
- Data.Json.Builder: instance [incoherent] Key Escaped
- Data.Json.Builder: instance [incoherent] Key Text
- Data.Json.Builder: instance [incoherent] Key [Char]
- Data.Json.Builder: instance [incoherent] Monoid Escaped
- Data.Json.Builder: instance [incoherent] Value Escaped
- Data.Json.Builder: newtype Escaped
+ Data.Json.Builder: class Value a => JsString a
+ Data.Json.Builder: data Escaped
+ Data.Json.Builder: data Json
+ Data.Json.Builder: instance [incoherent] (JsString k, Value a) => Value (HashMap k a)
+ Data.Json.Builder: instance [incoherent] (JsString k, Value a) => Value (Map k a)
+ Data.Json.Builder: instance [incoherent] JsString ByteString
+ Data.Json.Builder: instance [incoherent] JsString Text
+ Data.Json.Builder: instance [incoherent] JsString [Char]
+ Data.Json.Builder: toJson :: Value a => a -> Json
+ Data.Json.Builder: toJsonByteString :: Value a => a -> ByteString
+ Data.Json.Builder: toJsonLazyByteString :: Value a => a -> ByteString
+ Data.Json.Builder.Internal: Escaped :: Builder -> Escaped
+ Data.Json.Builder.Internal: Json :: Builder -> Json
+ Data.Json.Builder.Internal: class Value a => JsString a
+ Data.Json.Builder.Internal: class Value a
+ Data.Json.Builder.Internal: escape :: JsString a => a -> Escaped
+ Data.Json.Builder.Internal: instance JsString Escaped
+ Data.Json.Builder.Internal: instance Monoid Escaped
+ Data.Json.Builder.Internal: instance Value Escaped
+ Data.Json.Builder.Internal: instance Value Json
+ Data.Json.Builder.Internal: newtype Escaped
+ Data.Json.Builder.Internal: newtype Json
+ Data.Json.Builder.Internal: toJson :: Value a => a -> Json
- Data.Json.Builder: escape :: Key a => a -> Escaped
+ Data.Json.Builder: escape :: JsString a => a -> Escaped
- Data.Json.Builder: row :: (Key k, Value a) => k -> a -> Object
+ Data.Json.Builder: row :: (JsString k, Value a) => k -> a -> Object

Files

json-builder.cabal view
@@ -1,5 +1,5 @@ Name:                json-builder-Version:             0.0.1+Version:             0.1.0 Synopsis:            Data structure agnostic JSON serialization License:             BSD3 License-file:        LICENSE@@ -26,6 +26,7 @@ Library   hs-source-dirs: src   Exposed-modules:     Data.Json.Builder+                       Data.Json.Builder.Internal    Build-depends:       base >= 4 && < 5,                        blaze-builder,@@ -43,4 +44,4 @@ source-repository this   type:     git   location: http://github.com/lpsmith/json-builder-  tag:      v0.0.1+  tag:      v0.1.0
src/Data/Json/Builder.hs view
@@ -10,23 +10,28 @@ -- ----------------------------------------------------------------------------- -{-# LANGUAGE BangPatterns               #-}-{-# LANGUAGE ViewPatterns               #-}-{-# LANGUAGE OverloadedStrings          #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE IncoherentInstances        #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE ViewPatterns        #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE IncoherentInstances #-}  module Data.Json.Builder-     ( Key  (..)-     , Value(..)-     , Object-     , row+     ( Value(toJson)+     , Json+     , toBuilder+     , toJsonByteString+     , toJsonLazyByteString      , Array      , element-     , Escaped(..)+     , Object+     , row+     , JsString(escape)+     , Escaped      ) where +import           Prelude hiding ((++))+ import           Blaze.ByteString.Builder as Blaze                    ( Write                    , Builder@@ -36,7 +41,9 @@                    , writeByteString                    , fromWrite                    , fromWriteList-                   , writeWord8         )+                   , writeWord8+                   , toByteString+                   , toLazyByteString    ) import           Blaze.ByteString.Builder.Char.Utf8                    ( fromChar, writeChar, fromText, fromLazyText ) import           Blaze.Text (float, double, integral)@@ -60,72 +67,64 @@  import qualified Data.HashMap.Lazy      as HashMap --- | The 'Key' typeclass represents types that are rendered--- into json strings.  They are special because only strings--- can appear as field names of a json objects.--class Value a => Key a where-  escape           :: a -> Escaped---- | The 'Value' typeclass represents types that can be rendered--- into valid json syntax.--class Value a where-  toBuilder        :: a -> Blaze.Builder+import           Data.Json.Builder.Internal --- | The 'Escaped' type is a special Builder value that represents a UTF-8--- encoded string with all necessary characters json-escaped.  These builders--- must not render the opening or closing quotes,  which are instead rendered--- by 'toBuilder'.  This is so that Json strings can be efficiently constructed--- from multiple Haskell strings without actually concatinating the Haskell--- strings (which might require some kind of conversion in addition to--- concatination.)+(++) :: Monoid a => a -> a -> a+(++) = mappend+infixr 5 ++ -newtype Escaped = Escaped Blaze.Builder deriving (Monoid)+toBuilder :: Value a => a -> Builder+toBuilder x = case toJson x of+                Json y -> y+{-# SPECIALIZE toBuilder :: Json -> Builder #-}+{-# INLINE toBuilder #-} -instance Key Escaped where-  escape = id+toJsonByteString     :: Value a => a -> BS.ByteString+toJsonByteString     = toByteString     . toBuilder -instance Value Escaped where-  toBuilder (Escaped str) = fromChar '"' `mappend` str `mappend` fromChar '"'+toJsonLazyByteString :: Value a => a -> BL.ByteString+toJsonLazyByteString = toLazyByteString . toBuilder -type CommaTracker = (Bool -> Blaze.Builder) -> Bool -> Blaze.Builder+type CommaTracker = (Bool -> Builder) -> Bool -> Builder -comma :: Blaze.Builder -> CommaTracker-comma b f True  =                        b `mappend` f False-comma b f False = fromChar ',' `mappend` b `mappend` f False+comma :: Builder -> CommaTracker+comma b f True  =                 b ++ f False+comma b f False = fromChar ',' ++ b ++ f False {-# INLINE comma #-} --- |  The 'Object' type represents a builder that constructs syntax for a--- json object.  It has a singleton constructor 'row', and an instance of--- monoid, so that arbitrary objects can be constructed.  Note that--- duplicate field names will appear in the output, so it is up to the--- user of this interface to avoid duplicate field names.+-- |  The 'Object' type represents syntax for a json object.  It has a singleton+-- constructor 'row', and an instance of 'Monoid', so that 'mempty' represents the+-- empty object and 'mappend' concatinates two objects.  Arbitrary objects can+-- be constructed using these operators.+--+-- Note that duplicate field names will appear in the output, so it is up+-- to the user of this interface to avoid duplicate field names.  newtype Object = Object CommaTracker  instance Value Object where-  toBuilder (Object f) = fromChar '{' `mappend` f (\_ -> fromChar '}') True+  toJson (Object f) = Json (fromChar '{' ++ f (\_ -> fromChar '}') True)  instance Monoid Object where   mempty = Object id   mappend (Object f) (Object g) = Object (f . g) --- | The 'row' constructs a json object consisting of exactly one field.--- These objects can be concatinated using 'mappend'.-row :: (Key k, Value a) => k -> a -> Object+-- |  The 'row' function constructs a json object consisting of exactly+-- one field.  These objects can be concatinated using 'mappend'.+row :: (JsString k, Value a) => k -> a -> Object row k a = Object syntax   where     syntax = comma (mconcat [ toBuilder k, fromChar ':',  toBuilder a ]) --- |  The 'Array' type represents a builder that constructs syntax for a--- json array.  It has a singleton constructor 'element' and an instance of--- monoid, so that arbitrary arrays can be constructed.+-- |  The 'Array' type represents syntax for a json array.  It has been given+-- a singleton constructor 'element' and an instance of 'Monoid',  so that+-- 'mempty' represents the empty array and 'mappend' concatinates two arrays.+-- Arbitrary arrays can be constructed using these operators.  newtype Array = Array CommaTracker  instance Value Array where-  toBuilder (Array f) = fromChar '[' `mappend` f (\_ -> fromChar ']') True+  toJson (Array f) = Json (fromChar '[' ++ f (\_ -> fromChar ']') True)  instance Monoid Array where   mempty = Array id@@ -138,119 +137,123 @@  -- Primitive instances for json-builder +-- | renders as @null@ instance Value () where-  toBuilder _ = copyByteString "null"+  toJson _ = Json (copyByteString "null")  instance Value Int     where-  toBuilder = integral+  toJson = Json . integral  instance Value Int8    where-  toBuilder = integral+  toJson = Json . integral  instance Value Int16   where-  toBuilder = integral+  toJson = Json . integral  instance Value Int32   where-  toBuilder = integral+  toJson = Json . integral  instance Value Int64   where-  toBuilder = integral+  toJson = Json . integral  instance Value Integer where-  toBuilder = integral+  toJson = Json . integral  instance Value Word    where-  toBuilder = integral+  toJson = Json . integral  instance Value Word8   where-  toBuilder = integral+  toJson = Json . integral  instance Value Word16  where-  toBuilder = integral+  toJson = Json . integral  instance Value Word32  where-  toBuilder = integral+  toJson = Json . integral  instance Value Word64  where-  toBuilder = integral+  toJson = Json . integral  instance Value Double where-  toBuilder = double+  toJson = Json . double  instance Value Float where-  toBuilder = float+  toJson = Json . float +-- | renders as @true@ or @false@+ instance Value Bool where-  toBuilder True  = copyByteString "true"-  toBuilder False = copyByteString "false"+  toJson True  = Json (copyByteString "true")+  toJson False = Json (copyByteString "false") -instance Key BS.ByteString where+instance JsString BS.ByteString where   escape x = Escaped (loop x)     where       loop (BU.break quoteNeeded -> (a,b))-        = fromByteString a `mappend`+        = fromByteString a ++             case BU.decode b of               Nothing     ->  mempty-              Just (c,n)  ->  quoteChar c `mappend` loop (BS.drop n b)+              Just (c,n)  ->  quoteChar c ++ loop (BS.drop n b)  instance Value BS.ByteString where-  toBuilder = toBuilder . escape+  toJson = toJson . escape -instance Key BL.ByteString where+instance JsString BL.ByteString where   escape x = Escaped (loop x)     where       loop (BLU.break quoteNeeded -> (a,b))-        = fromLazyByteString a `mappend`+        = fromLazyByteString a ++             case BLU.decode b of               Nothing     ->  mempty-              Just (c,n)  ->  quoteChar c `mappend` loop (BL.drop n b)+              Just (c,n)  ->  quoteChar c ++ loop (BL.drop n b)  instance Value BL.ByteString where-  toBuilder = toBuilder . escape+  toJson = toJson . escape -instance Key T.Text where+instance JsString T.Text where   escape x = Escaped (loop x)     where       loop (T.break quoteNeeded -> (a,b))-        = fromText a `mappend`+        = fromText a ++             case T.uncons b of               Nothing      ->  mempty-              Just (c,b')  ->  quoteChar c `mappend` loop b'+              Just (c,b')  ->  quoteChar c ++ loop b'  instance Value T.Text where-  toBuilder = toBuilder . escape+  toJson = toJson . escape -instance Key TL.Text where+instance JsString TL.Text where   escape x = Escaped (loop x)     where       loop (TL.break quoteNeeded -> (a,b))-        = fromLazyText a `mappend`+        = fromLazyText a ++             case TL.uncons b of               Nothing      ->  mempty-              Just (c,b')  ->  quoteChar c `mappend` loop b'+              Just (c,b')  ->  quoteChar c ++ loop b'  instance Value TL.Text where-  toBuilder = toBuilder . escape+  toJson = toJson . escape -instance Key [Char] where+instance JsString [Char] where   escape str = Escaped (fromWriteList writeEscapedChar str)     where       writeEscapedChar c | quoteNeeded c = quoteCharW c                          | otherwise     = writeChar  c  instance Value [Char] where-  toBuilder = toBuilder . escape+  toJson = toJson . escape +-- | renders as an 'Array' instance Value a => Value [a] where-  toBuilder = toBuilder . mconcat . map element+  toJson = toJson . mconcat . map element -instance (Key k, Value a) => Value (Map.Map k a) where-  toBuilder = toBuilder-            . Map.foldrWithKey (\k a b -> row k a `mappend` b) mempty+-- | renders as an 'Object'+instance (JsString k, Value a) => Value (Map.Map k a) where+  toJson = toJson . Map.foldrWithKey     (\k a b -> row k a ++ b) mempty -instance (Key k, Value a) => Value (HashMap.HashMap k a) where-  toBuilder = toBuilder-            . HashMap.foldrWithKey (\k a b -> row k a `mappend` b) mempty+-- | renders as an 'Object'+instance (JsString k, Value a) => Value (HashMap.HashMap k a) where+  toJson = toJson . HashMap.foldrWithKey (\k a b -> row k a ++ b) mempty  ------------------------------------------------------------------------------ @@ -283,8 +286,8 @@ hexEscape  :: Char -> Write hexEscape  (c2w -> c)   = writeByteString "\\u00"-    `mappend` writeWord8 (char ((c `shiftR` 4) .&. 0xF))-    `mappend` writeWord8 (char ( c             .&. 0xF))+    ++ writeWord8 (char ((c `shiftR` 4) .&. 0xF))+    ++ writeWord8 (char ( c             .&. 0xF))  char :: Word8 -> Word8 char i | i < 10    = i + 48
+ src/Data/Json/Builder/Internal.hs view
@@ -0,0 +1,71 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Json.Builder.Internal+-- Copyright   :  (c) 2011 Leon P Smith+-- License     :  BSD3+--+-- Maintainer  :  Leon P Smith <leon@melding-monads.com>+--+-- Internal bits.   You can break this library's abstraction and emit+-- invalid Json syntax the constructors provided in this module.+-----------------------------------------------------------------------------++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Data.Json.Builder.Internal+     ( Value   (..)+     , Json    (..)+     , JsString(..)+     , Escaped (..)+     ) where++import Prelude hiding ((++))++import Blaze.ByteString.Builder+import Blaze.ByteString.Builder.Char.Utf8 ( fromChar )+import Data.ByteString(ByteString)+import Data.Monoid++(++) :: Monoid a => a -> a -> a+(++) = mappend+infixr 5 ++++-- | The 'Value' typeclass represents types that can be rendered+-- into valid json syntax.++class Value a where+  toJson :: a -> Json++-- | The 'Json' type represents valid json syntax.  It cannot be directly+-- analyzed, however it can be rendered into a 'ByteString' and used to+-- as a component of an array or an object to build a bigger json value.++newtype Json = Json Builder++instance Value Json where+  toJson = id++-- | The 'String' typeclass represents types that render into json string+-- syntax.  They are special because only strings can appear as field names+-- of json objects.++class Value a => JsString a where+  escape :: a -> Escaped++-- | The 'Escaped' type represents json string syntax.  The purpose of this+-- type is so that json strings can be efficiently constructed from multiple+-- Haskell strings without superfluous conversions or concatinations.+--+-- Internally, it is just a 'Builder' value which must produce a UTF-8 encoded+-- bytestring with backslashes,  quotes,  and control characters appropriately+-- escaped.   It also must not render the opening or closing quote,  which+-- are instead rendered by 'toJson'.++newtype Escaped = Escaped Builder deriving (Monoid)++instance Value    Escaped where+  toJson (Escaped str) = Json (fromChar '"' ++ str ++ fromChar '"')++instance JsString Escaped where+  escape = id+