@thigasdevelopment/luam 0.19.12 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lua/async.lua +6 -6
- package/lua/class.lua +239 -211
- package/lua/development-logs-client.lua +15 -9
- package/lua/development-logs-server.lua +41 -44
- package/lua/math.lua +21 -18
- package/lua/promise.lua +446 -0
- package/lua/string.lua +78 -62
- package/lua/table.lua +57 -49
- package/lua/threads.lua +326 -269
- package/lua/validate.lua +230 -185
- package/luam.mjs +969 -134
- package/package.json +1 -1
package/lua/threads.lua
CHANGED
|
@@ -1,274 +1,331 @@
|
|
|
1
1
|
local PRIORITIES = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
low = { pulsing = 250, frame = 8 },
|
|
3
|
+
normal = { pulsing = 100, frame = 15 },
|
|
4
|
+
high = { pulsing = 50, frame = 25 },
|
|
5
|
+
extreme = { pulsing = 0, frame = 50 }, -- Every pulse: the scheduler already runs on MTA's 50ms floor.
|
|
6
|
+
};
|
|
7
7
|
|
|
8
8
|
local STYLES = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
local self = setmetatable({}, Threads)
|
|
103
|
-
|
|
104
|
-
self.threads = {}
|
|
105
|
-
self.nextId, self.currentId = 0, -1
|
|
106
|
-
self.type, self.priority = 'concurrent', 'normal'
|
|
107
|
-
self.timer = nil
|
|
108
|
-
self:setType(style)
|
|
109
|
-
self:setPriority(priority)
|
|
110
|
-
|
|
111
|
-
return self
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
function Threads:add(func, options, ...)
|
|
115
|
-
options = options or {}
|
|
116
|
-
|
|
117
|
-
local thread = setmetatable({
|
|
118
|
-
routine = coroutine.create(func),
|
|
119
|
-
arguments = { ... },
|
|
120
|
-
paused = false,
|
|
121
|
-
started = false,
|
|
122
|
-
priority = options.priority or -1,
|
|
123
|
-
}, Thread)
|
|
124
|
-
|
|
125
|
-
local id = self.nextId + 1
|
|
126
|
-
self.nextId = id
|
|
127
|
-
self.threads[id] = thread
|
|
128
|
-
|
|
129
|
-
self:start()
|
|
130
|
-
return id
|
|
9
|
+
concurrent = true,
|
|
10
|
+
priority = true,
|
|
11
|
+
sequential = true,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
---@class Thread
|
|
15
|
+
---@field routine thread
|
|
16
|
+
---@field arguments table
|
|
17
|
+
---@field paused boolean
|
|
18
|
+
---@field started boolean
|
|
19
|
+
---@field priority number
|
|
20
|
+
---@field get fun(self: Thread): number
|
|
21
|
+
---@field set fun(self: Thread, priority: number): boolean
|
|
22
|
+
---@field pause fun(self: Thread): boolean
|
|
23
|
+
---@field resume fun(self: Thread): boolean
|
|
24
|
+
---@field isPaused fun(self: Thread): boolean
|
|
25
|
+
---@field isStarted fun(self: Thread): boolean
|
|
26
|
+
local Thread = {
|
|
27
|
+
---@param self Thread
|
|
28
|
+
---@return number
|
|
29
|
+
get = function (self)
|
|
30
|
+
return self.priority;
|
|
31
|
+
end,
|
|
32
|
+
|
|
33
|
+
---@param self Thread
|
|
34
|
+
---@param priority number
|
|
35
|
+
---@return boolean
|
|
36
|
+
set = function (self, priority)
|
|
37
|
+
priority = tonumber (priority);
|
|
38
|
+
if (not priority) or (self.priority == priority) then
|
|
39
|
+
return false;
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
self.priority = priority;
|
|
43
|
+
return true;
|
|
44
|
+
end,
|
|
45
|
+
|
|
46
|
+
---@param self Thread
|
|
47
|
+
---@return boolean
|
|
48
|
+
pause = function (self)
|
|
49
|
+
if (self.paused) then
|
|
50
|
+
return false;
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
self.paused = true;
|
|
54
|
+
return true;
|
|
55
|
+
end,
|
|
56
|
+
|
|
57
|
+
---@param self Thread
|
|
58
|
+
---@return boolean
|
|
59
|
+
resume = function (self)
|
|
60
|
+
if (not self.paused) then
|
|
61
|
+
return false;
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
self.paused = false;
|
|
65
|
+
return true;
|
|
66
|
+
end,
|
|
67
|
+
|
|
68
|
+
---@param self Thread
|
|
69
|
+
---@return boolean
|
|
70
|
+
isPaused = function (self)
|
|
71
|
+
return self.paused;
|
|
72
|
+
end,
|
|
73
|
+
|
|
74
|
+
---@param self Thread
|
|
75
|
+
---@return boolean
|
|
76
|
+
isStarted = function (self)
|
|
77
|
+
return self.started;
|
|
78
|
+
end,
|
|
79
|
+
};
|
|
80
|
+
Thread.__index = Thread;
|
|
81
|
+
|
|
82
|
+
---@param self Threads
|
|
83
|
+
---@param id number
|
|
84
|
+
---@param thread Thread
|
|
85
|
+
---@return boolean
|
|
86
|
+
local function resumeThread (self, id, thread)
|
|
87
|
+
if (coroutine.status (thread.routine) == 'dead') then
|
|
88
|
+
self:remove (id);
|
|
89
|
+
return false;
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if (thread:isPaused ()) or (Promise.isAwaiting (thread.routine)) then
|
|
93
|
+
return false;
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
if (thread:isStarted ()) then
|
|
97
|
+
return Promise.resume (thread.routine);
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
thread.started = true;
|
|
101
|
+
return Promise.resume (thread.routine, thread, unpack (thread.arguments));
|
|
131
102
|
end
|
|
132
103
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
function
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
104
|
+
---@class Threads
|
|
105
|
+
---@field threads table<number, Thread>
|
|
106
|
+
---@field nextId number
|
|
107
|
+
---@field currentId number
|
|
108
|
+
---@field type string
|
|
109
|
+
---@field priority string
|
|
110
|
+
---@field pulse fun()?
|
|
111
|
+
---@field pulsedAt number
|
|
112
|
+
---@field add fun(self: Threads, func: fun(...): any, options?: table, ...): number, Promise
|
|
113
|
+
---@field remove fun(self: Threads, id: number): boolean
|
|
114
|
+
---@field clear fun(self: Threads): boolean
|
|
115
|
+
---@field start fun(self: Threads): boolean
|
|
116
|
+
---@field stop fun(self: Threads)
|
|
117
|
+
---@field getType fun(self: Threads): string
|
|
118
|
+
---@field setType fun(self: Threads, style: string): boolean
|
|
119
|
+
---@field getPriority fun(self: Threads): string
|
|
120
|
+
---@field setPriority fun(self: Threads, priority: string): boolean
|
|
121
|
+
---@field getThread fun(self: Threads, id: number): Thread?
|
|
122
|
+
Threads = {
|
|
123
|
+
---@param style string
|
|
124
|
+
---@param priority string
|
|
125
|
+
---@return Threads
|
|
126
|
+
new = function (style, priority)
|
|
127
|
+
---@type Threads
|
|
128
|
+
local self = setmetatable ({ }, Threads);
|
|
129
|
+
|
|
130
|
+
self.threads = { };
|
|
131
|
+
self.nextId, self.currentId = 0, -1;
|
|
132
|
+
self.type, self.priority = 'concurrent', 'normal';
|
|
133
|
+
self.pulse, self.pulsedAt = nil, 0;
|
|
134
|
+
|
|
135
|
+
self:setType (style);
|
|
136
|
+
self:setPriority (priority);
|
|
137
|
+
|
|
138
|
+
return self;
|
|
139
|
+
end,
|
|
140
|
+
|
|
141
|
+
---@param self Threads
|
|
142
|
+
---@param func fun(...): any
|
|
143
|
+
---@param options? table
|
|
144
|
+
---@param ... any
|
|
145
|
+
---@return number, Promise
|
|
146
|
+
add = function (self, func, options, ...)
|
|
147
|
+
options = options or { };
|
|
148
|
+
|
|
149
|
+
---@type Thread
|
|
150
|
+
local thread = setmetatable ({
|
|
151
|
+
routine = coroutine.create (func),
|
|
152
|
+
arguments = { ... },
|
|
153
|
+
paused = false,
|
|
154
|
+
started = false,
|
|
155
|
+
priority = options.priority or -1,
|
|
156
|
+
}, Thread);
|
|
157
|
+
|
|
158
|
+
local settled = Promise.adopt (thread.routine);
|
|
159
|
+
|
|
160
|
+
local id = self.nextId + 1;
|
|
161
|
+
self.nextId = id;
|
|
162
|
+
self.threads[id] = thread;
|
|
163
|
+
|
|
164
|
+
self:start ();
|
|
165
|
+
return id, settled;
|
|
166
|
+
end,
|
|
167
|
+
|
|
168
|
+
---@param self Threads
|
|
169
|
+
---@param id number
|
|
170
|
+
---@return boolean
|
|
171
|
+
remove = function (self, id)
|
|
172
|
+
if (not self.threads[id]) then
|
|
173
|
+
return false;
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if (self.currentId == id) then
|
|
177
|
+
self.currentId = -1;
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
self.threads[id] = nil;
|
|
181
|
+
return true;
|
|
182
|
+
end,
|
|
183
|
+
|
|
184
|
+
---@param self Threads
|
|
185
|
+
---@return boolean
|
|
186
|
+
clear = function (self)
|
|
187
|
+
if (next (self.threads) == nil) then
|
|
188
|
+
return false;
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
self.threads, self.currentId = { }, -1;
|
|
192
|
+
|
|
193
|
+
self:stop ();
|
|
194
|
+
return true;
|
|
195
|
+
end,
|
|
196
|
+
|
|
197
|
+
---@param self Threads
|
|
198
|
+
---@return boolean
|
|
199
|
+
start = function (self)
|
|
200
|
+
if (self.pulse) then
|
|
201
|
+
return false;
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
self.pulse = Promise.pulse (function ()
|
|
205
|
+
self:process ();
|
|
206
|
+
end);
|
|
207
|
+
return true;
|
|
208
|
+
end,
|
|
209
|
+
|
|
210
|
+
---@param self Threads
|
|
211
|
+
stop = function (self)
|
|
212
|
+
if (self.pulse) then
|
|
213
|
+
Promise.unpulse (self.pulse);
|
|
214
|
+
end
|
|
215
|
+
self.pulse = nil;
|
|
216
|
+
end,
|
|
217
|
+
|
|
218
|
+
---@param self Threads
|
|
219
|
+
---@param sorted boolean
|
|
220
|
+
processQueue = function (self, sorted)
|
|
221
|
+
local queue = { };
|
|
222
|
+
|
|
223
|
+
for id, thread in pairs (self.threads) do
|
|
224
|
+
queue[#queue + 1] = { id = id, thread = thread };
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
if (sorted) then
|
|
228
|
+
table.sort (queue, function (left, right)
|
|
229
|
+
return left.thread:get () > right.thread:get ();
|
|
230
|
+
end);
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
local frames = 0;
|
|
234
|
+
for _, item in ipairs (queue) do
|
|
235
|
+
if (frames >= PRIORITIES[self.priority].frame) then return end
|
|
236
|
+
|
|
237
|
+
if (resumeThread (self, item.id, item.thread)) then
|
|
238
|
+
frames = frames + 1;
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end,
|
|
242
|
+
|
|
243
|
+
---@param self Threads
|
|
244
|
+
processSequential = function (self)
|
|
245
|
+
if (not self.threads[self.currentId]) then
|
|
246
|
+
self.currentId = -1;
|
|
247
|
+
|
|
248
|
+
for id in pairs (self.threads) do
|
|
249
|
+
self.currentId = id;
|
|
250
|
+
break;
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
local thread = self.threads[self.currentId];
|
|
255
|
+
if (not thread) then return end
|
|
256
|
+
|
|
257
|
+
local frames = 0;
|
|
258
|
+
while (frames < PRIORITIES[self.priority].frame) do
|
|
259
|
+
if (not resumeThread (self, self.currentId, thread)) then return end
|
|
260
|
+
|
|
261
|
+
frames = frames + 1;
|
|
262
|
+
end
|
|
263
|
+
end,
|
|
264
|
+
|
|
265
|
+
---@param self Threads
|
|
266
|
+
process = function (self)
|
|
267
|
+
local now = getTickCount ();
|
|
268
|
+
if ((now - self.pulsedAt) < PRIORITIES[self.priority].pulsing) then return end
|
|
269
|
+
|
|
270
|
+
self.pulsedAt = now;
|
|
271
|
+
|
|
272
|
+
if (self.type == 'sequential') then
|
|
273
|
+
self:processSequential ();
|
|
274
|
+
else
|
|
275
|
+
self:processQueue (self.type == 'priority');
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
if (next (self.threads) == nil) then
|
|
279
|
+
self:stop ();
|
|
280
|
+
end
|
|
281
|
+
end,
|
|
282
|
+
|
|
283
|
+
---@param self Threads
|
|
284
|
+
---@return string
|
|
285
|
+
getType = function (self)
|
|
286
|
+
return self.type;
|
|
287
|
+
end,
|
|
288
|
+
|
|
289
|
+
---@param self Threads
|
|
290
|
+
---@param style string
|
|
291
|
+
---@return boolean
|
|
292
|
+
setType = function (self, style)
|
|
293
|
+
if (type (style) ~= 'string') then
|
|
294
|
+
return false;
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
style = style:lower ();
|
|
298
|
+
if (not STYLES[style]) or (self.type == style) then
|
|
299
|
+
return false;
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
self.type = style;
|
|
303
|
+
return true;
|
|
304
|
+
end,
|
|
305
|
+
|
|
306
|
+
---@param self Threads
|
|
307
|
+
---@return string
|
|
308
|
+
getPriority = function (self)
|
|
309
|
+
return self.priority;
|
|
310
|
+
end,
|
|
311
|
+
|
|
312
|
+
---@param self Threads
|
|
313
|
+
---@param priority string
|
|
314
|
+
---@return boolean
|
|
315
|
+
setPriority = function (self, priority)
|
|
316
|
+
if (type (priority) ~= 'string') or (not PRIORITIES[priority]) or (self.priority == priority) then
|
|
317
|
+
return false;
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
self.priority = priority;
|
|
321
|
+
return true;
|
|
322
|
+
end,
|
|
323
|
+
|
|
324
|
+
---@param self Threads
|
|
325
|
+
---@param id number
|
|
326
|
+
---@return Thread?
|
|
327
|
+
getThread = function (self, id)
|
|
328
|
+
return self.threads[id];
|
|
329
|
+
end,
|
|
330
|
+
};
|
|
331
|
+
Threads.__index = Threads;
|