tests: enhances coverage for number parsing options
[luajson.git] / lua / json / encode / array.lua
blob3744409c160fa3bcdf69f1caf0bac65d67455f3f
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
5 local jsonutil = require("json.util")
7 local type = type
8 local pairs = pairs
9 local assert = assert
11 local table = require("table")
12 local math = require("math")
13 local table_concat = table.concat
14 local math_floor, math_modf = math.floor, math.modf
16 local jsonutil = require("json.util")
17 local util_IsArray = jsonutil.IsArray
19 local _ENV = nil
21 local defaultOptions = {
22 isArray = util_IsArray
25 local modeOptions = {}
27 local function mergeOptions(options, mode)
28 jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode])
29 end
31 --[[
32 Utility function to determine whether a table is an array or not.
33 Criteria for it being an array:
34 * ExternalIsArray returns true (or false directly reports not-array)
35 * If the table has an 'n' value that is an integer >= 1 then it
36 is an array... may result in false positives (should check some values
37 before it)
38 * It is a contiguous list of values with zero string-based keys
40 local function isArray(val, options)
41 local externalIsArray = options and options.isArray
43 if externalIsArray then
44 local ret = externalIsArray(val)
45 if ret == true or ret == false then
46 return ret
47 end
48 end
49 -- Use the 'n' element if it's a number
50 if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then
51 return true
52 end
53 local len = #val
54 for k,v in pairs(val) do
55 if type(k) ~= 'number' then
56 return false
57 end
58 local _, decim = math_modf(k)
59 if not (decim == 0 and 1<=k) then
60 return false
61 end
62 if k > len then -- Use Lua's length as absolute determiner
63 return false
64 end
65 end
67 return true
68 end
70 --[[
71 Cleanup function to unmark a value as in the encoding process and return
72 trailing results
74 local function unmarkAfterEncode(tab, state, ...)
75 state.already_encoded[tab] = nil
76 return ...
77 end
78 local function getEncoder(options)
79 options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
80 local function encodeArray(tab, state)
81 if not isArray(tab, options) then
82 return false
83 end
84 -- Make sure this value hasn't been encoded yet
85 state.check_unique(tab)
86 local encode = state.encode
87 local compositeEncoder = state.outputEncoder.composite
88 local valueEncoder = [[
89 for i = 1, (composite.n or #composite) do
90 local val = composite[i]
91 PUTINNER(i ~= 1)
92 val = encode(val, state)
93 val = val or ''
94 if val then
95 PUTVALUE(val)
96 end
97 end
99 return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state))
101 return { table = encodeArray }
104 local array = {
105 mergeOptions = mergeOptions,
106 isArray = isArray,
107 getEncoder = getEncoder
110 return array