local pairs = pairs
local ipairs = ipairs
local next = next
+local pcall = pcall
local getmetatable = getmetatable
+--- LuCI JSON-Library
+-- @cstyle instance
module "luci.json"
+
+--- Directly decode a JSON string
+-- @param json JSON-String
+-- @return Lua object
+function decode(json, ...)
+ local a = ActiveDecoder(function() return nil end, ...)
+ a.chunk = json
+ local s, obj = pcall(a.get, a)
+ return s and obj or nil
+end
+
+
+--- Direcly encode a Lua object into a JSON string.
+-- @param obj Lua Object
+-- @return JSON string
+function encode(obj, ...)
+ local out = {}
+ local e = Encoder(obj, 1, ...):source()
+ local chnk, err
+ repeat
+ chnk, err = e()
+ out[#out+1] = chnk
+ until chnk
+ return not err and table.concat(out) or nil
+end
+
+
--- Null replacement function
-- @return null
function null()
return null
end
-
+--- Create a new JSON-Encoder.
+-- @class function
+-- @name Encoder
+-- @param data Lua-Object to be encoded.
+-- @param buffersize Blocksize of returned data source.
+-- @param fastescape Use non-standard escaping (don't escape control chars)
+-- @return JSON-Encoder
Encoder = util.class()
---- Creates a new Encoder.
--- @param data Data to be encoded.
--- @param buffersize Buffersize of returned data.
--- @param fastescape Use non-standard escaping (don't escape control chars)
function Encoder.__init__(self, data, buffersize, fastescape)
self.data = data
self.buffersize = buffersize or 512
getmetatable(self).__call = Encoder.source
end
---- Create an LTN12 source from the encoder object
+--- Create an LTN12 source providing the encoded JSON-Data.
-- @return LTN12 source
function Encoder.source(self)
local source = coroutine.create(self.dispatch)
local first = true
if type(obj) == "table" then
- for i, entry in pairs(obj) do
+ for i=1, #obj do
first = first or self:put(",")
first = first and nil
- self:dispatch(entry)
+ self:dispatch(obj[i])
end
else
for entry in obj do
}
-
+--- Create a new JSON-Decoder.
+-- @class function
+-- @name Decoder
+-- @param customnull Use luci.json.null instead of nil for decoding null
+-- @return JSON-Decoder
Decoder = util.class()
---- Create a new Decoder object.
--- @param customnull User luci.json.null instead of nil
function Decoder.__init__(self, customnull)
self.cnull = customnull
getmetatable(self).__call = Decoder.sink
end
---- Create an LTN12 sink from the decoder object.
+--- Create an LTN12 sink from the decoder object which accepts the JSON-Data.
-- @return LTN12 sink
function Decoder.sink(self)
local sink = coroutine.create(self.dispatch)
end
---- Get the decoded data packets
+--- Get the decoded data packets after the rawdata has been sent to the sink.
-- @return Decoded data
function Decoder.get(self)
return self.data
['n'] = Decoder.parse_null,
['['] = Decoder.parse_array,
['{'] = Decoder.parse_object
-}
\ No newline at end of file
+}
+
+
+--- Create a new Active JSON-Decoder.
+-- @class function
+-- @name ActiveDecoder
+-- @param customnull Use luci.json.null instead of nil for decoding null
+-- @return Active JSON-Decoder
+ActiveDecoder = util.class(Decoder)
+
+function ActiveDecoder.__init__(self, source, customnull)
+ Decoder.__init__(self, customnull)
+ self.source = source
+ self.chunk = nil
+ getmetatable(self).__call = self.get
+end
+
+
+--- Fetches one JSON-object from given source
+-- @return Decoded object
+function ActiveDecoder.get(self)
+ local chunk, src_err, object
+ if not self.chunk then
+ chunk, src_err = self.source()
+ else
+ chunk = self.chunk
+ end
+
+ self.chunk, object = self:dispatch(chunk, src_err, true)
+ return object
+end
+
+
+function ActiveDecoder.fetch(self)
+ local chunk, src_err = self.source()
+ assert(chunk or not src_err, src_err)
+ return chunk
+end