--[[ Licensed according to the included 'LICENSE' document Author: Thomas Harning Jr ]] local setmetatable = setmetatable local assert, loadstring = assert, loadstring or load local _ENV = nil -- Key == weak, if main key goes away, then cache cleared local outputCache = setmetatable({}, {__mode = 'k'}) -- TODO: inner tables weak? local function buildFunction(nextValues, innerValue, valueWriter, innerWriter) local putInner = "" if innerValue and innerWriter then -- Prepare the lua-string representation of the separator to put in between values local formattedInnerValue = ("%q"):format(innerValue) -- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue) end -- Template-in the value writer (if present) and its conditional argument local functionCode = nextValues:gsub("PUTINNER(%b())", putInner) -- %VALUE% is to be filled in by the value-to-write valueWriter = valueWriter:gsub("%%VALUE%%", "%%1") -- Template-in the value writer with its argument functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter) functionCode = [[ return function(composite, ret, encode, state) ]] .. functionCode .. [[ end ]] return assert(loadstring(functionCode))() end local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter) local cache = outputCache[cacheKey] if not cache then cache = {} outputCache[cacheKey] = cache end local fun = cache[nextValues] if not fun then fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter) cache[nextValues] = fun end return fun end local output_utility = { prepareEncoder = prepareEncoder } return output_utility