Annotate

util/template.lua @ 13182:c48ae06e24d6

util.datamanager: Fix indexing first item if not at the very start If the first item does not start at position 0 then the index function produces a phantom first entry covering position zero until where the real first item starts. When using the index, this would make it either appear as the first item was missing or cause an off-by-one issue with remaining items.
author Kim Alvefur <zash@zash.se>
date Mon, 10 Jul 2023 17:19:05 +0200
parent 12975:d10957394a3c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
7196
94ec474debf5 util.template: Silence luacheck warnings about unused loop vars
Kim Alvefur <zash@zash.se>
parents: 6777
diff changeset
1 -- luacheck: ignore 213/i
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 8555
diff changeset
2 local stanza_mt = require "prosody.util.stanza".stanza_mt;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
3 local setmetatable = setmetatable;
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
4 local pairs = pairs;
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
5 local ipairs = ipairs;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
6 local error = error;
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 8555
diff changeset
7 local envload = require "prosody.util.envload".envload;
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
8 local debug = debug;
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
9 local t_remove = table.remove;
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 8555
diff changeset
10 local parse_xml = require "prosody.util.xml".parse;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
11
6777
5de6b93d0190 util.*: Remove use of module() function, make all module functions local and return them in a table at the end
Kim Alvefur <zash@zash.se>
parents: 5214
diff changeset
12 local _ENV = nil;
8555
4f0f5b49bb03 vairious: Add annotation when an empty environment is set [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8418
diff changeset
13 -- luacheck: std none
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
14
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
15 local function trim_xml(stanza)
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
16 for i=#stanza,1,-1 do
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
17 local child = stanza[i];
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
18 if child.name then
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
19 trim_xml(child);
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
20 else
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
21 child = child:gsub("^%s*", ""):gsub("%s*$", "");
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
22 stanza[i] = child;
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
23 if child == "" then t_remove(stanza, i); end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
24 end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
25 end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
26 end
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
27
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
28 local function create_string_string(str)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
29 str = ("%q"):format(str);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
30 str = str:gsub("{([^}]*)}", function(s)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
31 return '"..(data["'..s..'"]or"").."';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
32 end);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
33 return str;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
34 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
35 local function create_attr_string(attr, xmlns)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
36 local str = '{';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
37 for name,value in pairs(attr) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
38 if name ~= "xmlns" or value ~= xmlns then
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
39 str = str..("[%q]=%s;"):format(name, create_string_string(value));
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
40 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
41 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
42 return str..'}';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
43 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
44 local function create_clone_string(stanza, lookup, xmlns)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
45 if not lookup[stanza] then
3640
4bc88bb748d1 util.template: Don't add stanza.last_add. 20% faster.
Waqas Hussain <waqas20@gmail.com>
parents: 3637
diff changeset
46 local s = ('setmetatable({name=%q,attr=%s,tags={'):format(stanza.name, create_attr_string(stanza.attr, xmlns));
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
47 -- add tags
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
48 for i,tag in ipairs(stanza.tags) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
49 s = s..create_clone_string(tag, lookup, stanza.attr.xmlns)..";";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
50 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
51 s = s..'};';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
52 -- add children
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
53 for i,child in ipairs(stanza) do
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
54 if child.name then
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
55 s = s..create_clone_string(child, lookup, stanza.attr.xmlns)..";";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
56 else
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
57 s = s..create_string_string(child)..";"
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
58 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
59 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
60 s = s..'}, stanza_mt)';
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
61 s = s:gsub('%.%.""', ""):gsub('([=;])""%.%.', "%1"):gsub(';"";', ";"); -- strip empty strings
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
62 local n = #lookup + 1;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
63 lookup[n] = s;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
64 lookup[stanza] = "_"..n;
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
65 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
66 return lookup[stanza];
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
67 end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
68 local function create_cloner(stanza, chunkname)
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
69 local lookup = {};
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
70 local name = create_clone_string(stanza, lookup, "");
7197
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7196
diff changeset
71 local src = "local setmetatable,stanza_mt=...;return function(data)";
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
72 for i=1,#lookup do
7197
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7196
diff changeset
73 src = src.."local _"..i.."="..lookup[i]..";";
3546
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
74 end
7197
ff514c1b1c27 util.template: Use separate variables for source and compiled function [luacheck]
Kim Alvefur <zash@zash.se>
parents: 7196
diff changeset
75 src = src.."return "..name..";end";
8418
ad1e10c93b41 util.template: Use util.envload instead of loadstring which is deprecated in Lua 5.2
Kim Alvefur <zash@zash.se>
parents: 7197
diff changeset
76 local f,err = envload(src, chunkname);
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
77 if not f then error(err); end
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
78 return f(setmetatable, stanza_mt);
3546
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
79 end
cb1600dea3ad util.template: Optimized to be almost as fast as manual stanza building.
Waqas Hussain <waqas20@gmail.com>
parents: 3545
diff changeset
80
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
81 local template_mt = { __tostring = function(t) return t.name end };
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
82 local function create_template(templates, text)
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
83 local stanza, err = parse_xml(text);
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
84 if not stanza then error(err); end
4495
c0f5c78cb817 util.template: Refactoring to make the string->stanza conversion code more generic.
Waqas Hussain <waqas20@gmail.com>
parents: 3640
diff changeset
85 trim_xml(stanza);
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
86
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
87 local info = debug.getinfo(3, "Sl");
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
88 info = info and ("template(%s:%d)"):format(info.short_src:match("[^\\/]*$"), info.currentline) or "template(unknown)";
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
89
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
90 local template = setmetatable({ apply = create_cloner(stanza, info), name = info, text = text }, template_mt);
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
91 templates[text] = template;
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
92 return template;
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
93 end
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
94
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
95 local templates = setmetatable({}, { __mode = 'k', __index = create_template });
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
96 return function(text)
3637
bd491def3efb util.template: Rewritten to be much faster than the util.stanza stanza building API.
Waqas Hussain <waqas20@gmail.com>
parents: 3546
diff changeset
97 return templates[text];
3545
c85f9a4ae1c4 util.template: Initial commit. A template library for XML stanzas.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
98 end;