encoder: Break apart the encoder into distinct modules + add call encoding
[luajson.git] / src / json / encode.lua
blob2a93f337a17378e134bed3ad5d0f01b416f7746e
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
5 local type = type
6 local assert = assert
7 local getmetatable, setmetatable = getmetatable, setmetatable
8 local util = require("json.util")
9 local null = util.null
11 local require = require
13 local strings = require("json.encode.strings")
14 local others = require("json.encode.others")
16 module("json.encode")
18 -- Load these modules after defining that json.encode exists
19 -- calls, object, and array need encodeValue and isEncodable
20 local calls = require("json.encode.calls")
21 local array = require("json.encode.array")
22 local object = require("json.encode.object")
25 local function encodeFunction(val, options)
26 if val ~= null and calls.isCall(val, options) then
27 return calls.encode(val, options)
28 end
29 return 'null'
30 end
32 local alreadyEncoded -- Table set at the beginning of every
33 -- encoding operation to empty to detect recursiveness
34 local function encodeTable(tab, options)
35 assert(not alreadyEncoded[tab], "Recursive table detected")
36 alreadyEncoded[tab] = true
37 -- Pass off encoding to appropriate encoder
38 if calls.isCall(tab, options) then
39 return calls.encode(tab, options)
40 elseif array.isArray(tab, options) then
41 return array.encode(tab, options)
42 else
43 return object.encode(tab, options)
44 end
45 end
47 local encodeMapping = {
48 ['table' ] = encodeTable,
49 ['number' ] = others.encodeNumber,
50 ['boolean'] = others.encodeBoolean,
51 ['function'] = encodeFunction,
52 ['string' ] = strings.encode,
53 ['nil'] = others.encodeNil -- For the case that nils are encountered count them as nulls
55 function isEncodable(item, options)
56 local isNotEncodableFunction = type(item) == 'function' and (item ~= null and not calls.isCall(item, options))
57 return encodeMapping[type(item)] and not isNotEncodableFunction
58 end
60 function encodeValue(item, options)
61 local itemType = type(item)
62 local encoder = encodeMapping[itemType]
63 assert(encoder, "Invalid item to encode: " .. itemType)
64 return encoder(item, options)
65 end
67 local defaultOptions = {
68 strings = {
69 preProcess = false
71 array = {
72 isArray = util.IsArray
76 function encode(data, options)
77 options = options or defaultOptions
78 alreadyEncoded = {}
79 return encodeValue(data, options)
80 end
82 local mt = getmetatable(_M) or {}
83 mt.__call = function(self, ...)
84 return encode(...)
85 end
86 setmetatable(_M, mt)