blob: 45e300c8af46fc5e3967f23d7a12c29d2c66aaf1 [file] [log] [blame]
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local jsonutil = require("json.util")
local type = type
local pairs = pairs
local assert = assert
local table = require("table")
local math = require("math")
local table_concat = table.concat
local math_floor, math_modf = math.floor, math.modf
local util_merge = require("json.util").merge
local util_IsArray = require("json.util").IsArray
module("json.encode.array")
local defaultOptions = {
isArray = util_IsArray
}
default = nil
strict = nil
--[[
Utility function to determine whether a table is an array or not.
Criteria for it being an array:
* ExternalIsArray returns true (or false directly reports not-array)
* If the table has an 'n' value that is an integer >= 1 then it
is an array... may result in false positives (should check some values
before it)
* It is a contiguous list of values with zero string-based keys
]]
function isArray(val, options)
local externalIsArray = options and options.isArray
if externalIsArray then
local ret = externalIsArray(val)
if ret == true or ret == false then
return ret
end
end
-- Use the 'n' element if it's a number
if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then
return true
end
local len = #val
for k,v in pairs(val) do
if type(k) ~= 'number' then
return false
end
local _, decim = math_modf(k)
if not (decim == 0 and 1<=k) then
return false
end
if k > len then -- Use Lua's length as absolute determiner
return false
end
end
return true
end
--[[
Cleanup function to unmark a value as in the encoding process and return
trailing results
]]
local function unmarkAfterEncode(tab, state, ...)
state.already_encoded[tab] = nil
return ...
end
function getEncoder(options)
options = options and util_merge({}, defaultOptions, options) or defaultOptions
local function encodeArray(tab, state)
if not isArray(tab, options) then
return false
end
-- Make sure this value hasn't been encoded yet
state.check_unique(tab)
local encode = state.encode
local compositeEncoder = state.outputEncoder.composite
local valueEncoder = [[
for i = 1, (composite.n or #composite) do
local val = composite[i]
PUTINNER(i ~= 1)
val = encode(val, state)
val = val or ''
if val then
PUTVALUE(val)
end
end
]]
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state))
end
return { table = encodeArray }
end