{-# LANGUAGE TypeSynonymInstances
  #-}


module Text.JSON.Escape where


import Data.Char
import Data.List
import qualified Data.ByteString.Lazy.Char8 as Lazy
import qualified Data.ByteString.Char8 as Strict




{-| Class of JSON escapable text. The solidus (@/@) is always escaped, as are
    all ASCII control characters. Non-ASCII control characters and Unicode
    printable characters above ASCII are left as is.
 -}
class Escape t where
  escape                    ::  t -> t
instance Escape Strict.ByteString where
  escape                     =  Strict.concatMap (Strict.pack . esc)
instance Escape Lazy.ByteString where
  escape                     =  Lazy.concatMap (Lazy.pack . esc)
instance Escape String where
  escape                     =  concatMap esc


{-| Escapes an individual character for embedding in a JSON string.
 -}
esc                         ::  Char -> String
esc c                        =  case c of
  '"'                       ->  "\\\""
  '\\'                      ->  "\\\\"
  '/'                       ->  "\\/"
  '\NUL'                    ->  "\\u0000"
  '\SOH'                    ->  "\\u0001"
  '\STX'                    ->  "\\u0002"
  '\ETX'                    ->  "\\u0003"
  '\EOT'                    ->  "\\u0004"
  '\ENQ'                    ->  "\\u0005"
  '\ACK'                    ->  "\\u0006"
  '\a'                      ->  "\\u0007"
  '\b'                      ->  "\\b"
  '\t'                      ->  "\\t"
  '\n'                      ->  "\\n"
  '\v'                      ->  "\\u000b"
  '\f'                      ->  "\\f"
  '\r'                      ->  "\\r"
  '\SO'                     ->  "\\u000e"
  '\SI'                     ->  "\\u000f"
  '\DLE'                    ->  "\\u0010"
  '\DC1'                    ->  "\\u0011"
  '\DC2'                    ->  "\\u0012"
  '\DC3'                    ->  "\\u0013"
  '\DC4'                    ->  "\\u0014"
  '\NAK'                    ->  "\\u0015"
  '\SYN'                    ->  "\\u0016"
  '\ETB'                    ->  "\\u0017"
  '\CAN'                    ->  "\\u0018"
  '\EM'                     ->  "\\u0019"
  '\SUB'                    ->  "\\u001a"
  '\ESC'                    ->  "\\u001b"
  '\FS'                     ->  "\\u001c"
  '\GS'                     ->  "\\u001d"
  '\RS'                     ->  "\\u001e"
  '\US'                     ->  "\\u001f"
  '\DEL'                    ->  "\\u007f"
  _                         ->  [c]


escaped c                    =  esc c /= [c]