@axpecter/lync 1.3.0
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/README.md +300 -0
- package/package.json +38 -0
- package/src/Types.luau +63 -0
- package/src/api/Group.luau +126 -0
- package/src/api/Namespace.luau +226 -0
- package/src/api/Packet.luau +147 -0
- package/src/api/Query.luau +295 -0
- package/src/api/Signal.luau +224 -0
- package/src/codec/Base.luau +49 -0
- package/src/codec/composite/Array.luau +275 -0
- package/src/codec/composite/Map.luau +395 -0
- package/src/codec/composite/Optional.luau +47 -0
- package/src/codec/composite/Shared.luau +151 -0
- package/src/codec/composite/Struct.luau +440 -0
- package/src/codec/composite/Tagged.luau +222 -0
- package/src/codec/composite/Tuple.luau +143 -0
- package/src/codec/datatype/Buffer.luau +44 -0
- package/src/codec/datatype/CFrame.luau +51 -0
- package/src/codec/datatype/Color.luau +22 -0
- package/src/codec/datatype/Instance.luau +48 -0
- package/src/codec/datatype/IntVector.luau +25 -0
- package/src/codec/datatype/NumberRange.luau +14 -0
- package/src/codec/datatype/Ray.luau +27 -0
- package/src/codec/datatype/Rect.luau +21 -0
- package/src/codec/datatype/Region.luau +58 -0
- package/src/codec/datatype/Sequence.luau +129 -0
- package/src/codec/datatype/String.luau +87 -0
- package/src/codec/datatype/UDim.luau +27 -0
- package/src/codec/datatype/Vector.luau +25 -0
- package/src/codec/meta/Auto.luau +353 -0
- package/src/codec/meta/Bitfield.luau +191 -0
- package/src/codec/meta/Custom.luau +27 -0
- package/src/codec/meta/Enum.luau +80 -0
- package/src/codec/meta/Nothing.luau +9 -0
- package/src/codec/meta/Quantized.luau +170 -0
- package/src/codec/meta/Unknown.luau +35 -0
- package/src/codec/primitive/Bool.luau +30 -0
- package/src/codec/primitive/Float16.luau +111 -0
- package/src/codec/primitive/Number.luau +48 -0
- package/src/codec/primitive/Varint.luau +76 -0
- package/src/index.d.ts +279 -0
- package/src/init.luau +161 -0
- package/src/internal/Baseline.luau +41 -0
- package/src/internal/Channel.luau +235 -0
- package/src/internal/Middleware.luau +109 -0
- package/src/internal/Pool.luau +68 -0
- package/src/internal/Registry.luau +146 -0
- package/src/transport/Bridge.luau +66 -0
- package/src/transport/Client.luau +151 -0
- package/src/transport/Gate.luau +222 -0
- package/src/transport/Reader.luau +175 -0
- package/src/transport/Server.luau +364 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- O(1) disconnect listener system with thread reuse.
|
|
4
|
+
|
|
5
|
+
local Types = require (script.Parent.Parent.Types)
|
|
6
|
+
|
|
7
|
+
type Connection = Types.Connection
|
|
8
|
+
|
|
9
|
+
-- Listener state: single numeric field for both connected and once checks.
|
|
10
|
+
local STATE_DISCONNECTED = 0
|
|
11
|
+
local STATE_CONNECTED = 1
|
|
12
|
+
local STATE_ONCE = 2
|
|
13
|
+
|
|
14
|
+
-- Private ----------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
local _freeThread: thread? = nil
|
|
17
|
+
|
|
18
|
+
local function passer (fn: (...any) -> (), ...: any): ()
|
|
19
|
+
local acquired = _freeThread
|
|
20
|
+
_freeThread = nil
|
|
21
|
+
fn (...)
|
|
22
|
+
_freeThread = acquired
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
local function yielder (): ()
|
|
26
|
+
while true do
|
|
27
|
+
passer (coroutine.yield ())
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
local function spawn (fn: (...any) -> (), ...: any): ()
|
|
32
|
+
if not _freeThread then
|
|
33
|
+
_freeThread = coroutine.create (yielder)
|
|
34
|
+
coroutine.resume (_freeThread :: thread)
|
|
35
|
+
end
|
|
36
|
+
task.spawn (_freeThread :: thread, fn, ...)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
-- Entry doubles as the Connection handle , 1 alloc per listener instead of 2.
|
|
40
|
+
local EntryImpl = {}
|
|
41
|
+
EntryImpl.__index = EntryImpl
|
|
42
|
+
|
|
43
|
+
function EntryImpl.disconnect (self: any): ()
|
|
44
|
+
if self._state == STATE_DISCONNECTED then
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
self._state = STATE_DISCONNECTED
|
|
49
|
+
self.connected = false
|
|
50
|
+
|
|
51
|
+
local entries = self._signal._entries
|
|
52
|
+
local count = self._signal._count
|
|
53
|
+
local index = self._index
|
|
54
|
+
|
|
55
|
+
if count == 0 or index > count then
|
|
56
|
+
return
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if index < count then
|
|
60
|
+
local last = entries[count]
|
|
61
|
+
entries[index] = last
|
|
62
|
+
last._index = index
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
entries[count] = nil
|
|
66
|
+
self._signal._count = count - 1
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
local SignalImpl = {}
|
|
70
|
+
SignalImpl.__index = SignalImpl
|
|
71
|
+
|
|
72
|
+
local function addEntry (self: any, callback: (...any) -> (), isOnce: boolean): Connection
|
|
73
|
+
local count = self._count + 1
|
|
74
|
+
self._count = count
|
|
75
|
+
|
|
76
|
+
local entry = setmetatable ({
|
|
77
|
+
fn = callback,
|
|
78
|
+
_state = if isOnce then STATE_ONCE else STATE_CONNECTED,
|
|
79
|
+
connected = true,
|
|
80
|
+
_signal = self,
|
|
81
|
+
_index = count,
|
|
82
|
+
}, EntryImpl)
|
|
83
|
+
|
|
84
|
+
self._entries[count] = entry
|
|
85
|
+
return entry :: any
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
function SignalImpl.connect (self: any, callback: (...any) -> ()): Connection
|
|
89
|
+
return addEntry (self, callback, false)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
function SignalImpl.once (self: any, callback: (...any) -> ()): Connection
|
|
93
|
+
return addEntry (self, callback, true)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
function SignalImpl.wait (self: any): ...any
|
|
97
|
+
local thread = coroutine.running ()
|
|
98
|
+
local entry: any
|
|
99
|
+
|
|
100
|
+
entry = addEntry (self, function (...: any): ()
|
|
101
|
+
entry:disconnect ()
|
|
102
|
+
task.spawn (thread, ...)
|
|
103
|
+
end, true)
|
|
104
|
+
|
|
105
|
+
return coroutine.yield ()
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
-- Dispatches to all listeners via task.spawn (safe for yielding handlers).
|
|
109
|
+
function SignalImpl.fire (self: any, ...: any): ()
|
|
110
|
+
local entries = self._entries
|
|
111
|
+
local count = self._count
|
|
112
|
+
if count == 0 then
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if count == 1 then
|
|
117
|
+
local entry = entries[1]
|
|
118
|
+
local state = entry._state
|
|
119
|
+
if state == STATE_DISCONNECTED then
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
spawn (entry.fn, ...)
|
|
124
|
+
|
|
125
|
+
if state == STATE_ONCE then
|
|
126
|
+
entry:disconnect ()
|
|
127
|
+
end
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
local snapshot = self._snapshot
|
|
132
|
+
table.move (entries, 1, count, 1, snapshot)
|
|
133
|
+
|
|
134
|
+
local tail = count + 1
|
|
135
|
+
if snapshot[tail] ~= nil then
|
|
136
|
+
snapshot[tail] = nil
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
for i = 1, count do
|
|
140
|
+
local entry = snapshot[i]
|
|
141
|
+
snapshot[i] = nil
|
|
142
|
+
|
|
143
|
+
local state = entry._state
|
|
144
|
+
if state == STATE_DISCONNECTED then
|
|
145
|
+
continue
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
spawn (entry.fn, ...)
|
|
149
|
+
|
|
150
|
+
if state == STATE_ONCE then
|
|
151
|
+
entry:disconnect ()
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
-- Synchronous dispatch. Only safe when all listeners are non-yielding.
|
|
157
|
+
function SignalImpl.fireSync (self: any, ...: any): ()
|
|
158
|
+
local entries = self._entries
|
|
159
|
+
local count = self._count
|
|
160
|
+
if count == 0 then
|
|
161
|
+
return
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
if count == 1 then
|
|
165
|
+
local entry = entries[1]
|
|
166
|
+
local state = entry._state
|
|
167
|
+
if state == STATE_DISCONNECTED then
|
|
168
|
+
return
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
entry.fn (...)
|
|
172
|
+
|
|
173
|
+
if state == STATE_ONCE then
|
|
174
|
+
entry:disconnect ()
|
|
175
|
+
end
|
|
176
|
+
return
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
local snapshot = self._snapshot
|
|
180
|
+
table.move (entries, 1, count, 1, snapshot)
|
|
181
|
+
|
|
182
|
+
local tail = count + 1
|
|
183
|
+
if snapshot[tail] ~= nil then
|
|
184
|
+
snapshot[tail] = nil
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
for i = 1, count do
|
|
188
|
+
local entry = snapshot[i]
|
|
189
|
+
snapshot[i] = nil
|
|
190
|
+
|
|
191
|
+
local state = entry._state
|
|
192
|
+
if state == STATE_DISCONNECTED then
|
|
193
|
+
continue
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
entry.fn (...)
|
|
197
|
+
|
|
198
|
+
if state == STATE_ONCE then
|
|
199
|
+
entry:disconnect ()
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
function SignalImpl.disconnectAll (self: any): ()
|
|
205
|
+
local entries = self._entries
|
|
206
|
+
|
|
207
|
+
for i = 1, self._count do
|
|
208
|
+
entries[i]._state = STATE_DISCONNECTED
|
|
209
|
+
entries[i].connected = false
|
|
210
|
+
entries[i] = nil
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
self._count = 0
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
-- Public -----------------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
local Signal = {}
|
|
219
|
+
|
|
220
|
+
function Signal.create (): any
|
|
221
|
+
return setmetatable ({ _entries = {}, _count = 0, _snapshot = {} }, SignalImpl)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
return table.freeze (Signal)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!native
|
|
3
|
+
-- Fixed-size codec factory. Every fixed-size codec calls Base.define once.
|
|
4
|
+
|
|
5
|
+
local Channel = require (script.Parent.Parent.internal.Channel)
|
|
6
|
+
local alloc = Channel.alloc
|
|
7
|
+
|
|
8
|
+
-- Public -----------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
local Base = {}
|
|
11
|
+
|
|
12
|
+
function Base.define <T>(
|
|
13
|
+
size: number,
|
|
14
|
+
directWrite: (b: buffer, offset: number, value: T) -> (),
|
|
15
|
+
directRead: (b: buffer, offset: number) -> T
|
|
16
|
+
): any
|
|
17
|
+
return table.freeze ({
|
|
18
|
+
_size = size,
|
|
19
|
+
_directWrite = directWrite,
|
|
20
|
+
_directRead = directRead,
|
|
21
|
+
write = function (ch: any, value: T): ()
|
|
22
|
+
local c = ch.cursor
|
|
23
|
+
if c + size > ch.size then
|
|
24
|
+
alloc (ch, size)
|
|
25
|
+
end
|
|
26
|
+
directWrite (ch.buff, c, value)
|
|
27
|
+
ch.cursor = c + size
|
|
28
|
+
end,
|
|
29
|
+
read = function (src: buffer, pos: number, _refs: { Instance }?): (T, number)
|
|
30
|
+
return directRead (src, pos), size
|
|
31
|
+
end,
|
|
32
|
+
})
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
function Base.zero (): any
|
|
36
|
+
return table.freeze ({
|
|
37
|
+
_size = 0,
|
|
38
|
+
_directWrite = function (_b: buffer, _offset: number, _value: any): () end,
|
|
39
|
+
_directRead = function (_b: buffer, _offset: number): any
|
|
40
|
+
return nil
|
|
41
|
+
end,
|
|
42
|
+
write = function (_ch: any, _value: any): () end,
|
|
43
|
+
read = function (_src: buffer, _pos: number, _refs: { Instance }?): (any, number)
|
|
44
|
+
return nil, 0
|
|
45
|
+
end,
|
|
46
|
+
})
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return table.freeze (Base)
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!native
|
|
3
|
+
-- array and deltaArray codecs.
|
|
4
|
+
|
|
5
|
+
local Baseline = require (script.Parent.Parent.Parent.internal.Baseline)
|
|
6
|
+
local Channel = require (script.Parent.Parent.Parent.internal.Channel)
|
|
7
|
+
local alloc = Channel.alloc
|
|
8
|
+
local Shared = require (script.Parent.Shared)
|
|
9
|
+
local Types = require (script.Parent.Parent.Parent.Types)
|
|
10
|
+
|
|
11
|
+
type ChannelState = Types.ChannelState
|
|
12
|
+
type Codec<T> = Types.Codec<T>
|
|
13
|
+
local Varint = require (script.Parent.Parent.primitive.Varint)
|
|
14
|
+
|
|
15
|
+
local rangeEqual = Shared.rangeEqual
|
|
16
|
+
local acquireScratch = Shared.acquireScratch
|
|
17
|
+
local releaseScratch = Shared.releaseScratch
|
|
18
|
+
|
|
19
|
+
local FLAG_DELTA = Shared.FLAG_DELTA
|
|
20
|
+
local FLAG_FULL = Shared.FLAG_FULL
|
|
21
|
+
local FLAG_UNCHANGED = Shared.FLAG_UNCHANGED
|
|
22
|
+
|
|
23
|
+
-- Public -----------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
local Array = {}
|
|
26
|
+
|
|
27
|
+
function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any }>
|
|
28
|
+
local deltaId = Shared.allocDeltaId ()
|
|
29
|
+
|
|
30
|
+
local writeElement = element.write
|
|
31
|
+
local readElement = element.read
|
|
32
|
+
|
|
33
|
+
local elemSize = (element :: any)._size :: number?
|
|
34
|
+
local elemDirect = (element :: any)._directWrite
|
|
35
|
+
local elemDRead = (element :: any)._directRead
|
|
36
|
+
|
|
37
|
+
return table.freeze ({
|
|
38
|
+
_isDelta = true,
|
|
39
|
+
|
|
40
|
+
write = function (ch: ChannelState, value: { any }): ()
|
|
41
|
+
local len = #value
|
|
42
|
+
local cache = ch.deltas[deltaId] :: { raw: buffer, bounds: { number }, len: number }?
|
|
43
|
+
local scratch = acquireScratch ()
|
|
44
|
+
|
|
45
|
+
local bounds = table.create (len + 1)
|
|
46
|
+
bounds[1] = 0
|
|
47
|
+
|
|
48
|
+
if elemDirect and elemSize then
|
|
49
|
+
local totalBytes = len * elemSize
|
|
50
|
+
alloc (scratch, totalBytes)
|
|
51
|
+
local b = scratch.buff
|
|
52
|
+
local c = 0
|
|
53
|
+
for i = 1, len do
|
|
54
|
+
elemDirect (b, c, value[i])
|
|
55
|
+
c += elemSize
|
|
56
|
+
bounds[i + 1] = c
|
|
57
|
+
end
|
|
58
|
+
scratch.cursor = totalBytes
|
|
59
|
+
else
|
|
60
|
+
for i = 1, len do
|
|
61
|
+
writeElement (scratch, value[i])
|
|
62
|
+
bounds[i + 1] = scratch.cursor
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
local scratchTotal = scratch.cursor
|
|
67
|
+
|
|
68
|
+
if not cache or cache.len ~= len then
|
|
69
|
+
alloc (ch, 1)
|
|
70
|
+
buffer.writeu8 (ch.buff, ch.cursor, FLAG_FULL)
|
|
71
|
+
ch.cursor += 1
|
|
72
|
+
Varint.write (ch, len)
|
|
73
|
+
|
|
74
|
+
alloc (ch, scratchTotal)
|
|
75
|
+
buffer.copy (ch.buff, ch.cursor, scratch.buff, 0, scratchTotal)
|
|
76
|
+
ch.cursor += scratchTotal
|
|
77
|
+
else
|
|
78
|
+
local cacheRaw = cache.raw
|
|
79
|
+
local cacheBds = cache.bounds
|
|
80
|
+
local dirty = table.create (len)
|
|
81
|
+
local dirtyN = 0
|
|
82
|
+
|
|
83
|
+
for i = 1, len do
|
|
84
|
+
local newOff = bounds[i]
|
|
85
|
+
local newLen = bounds[i + 1] - newOff
|
|
86
|
+
local oldOff = cacheBds[i]
|
|
87
|
+
local oldLen = cacheBds[i + 1] - oldOff
|
|
88
|
+
|
|
89
|
+
if
|
|
90
|
+
newLen ~= oldLen
|
|
91
|
+
or not rangeEqual (scratch.buff, newOff, cacheRaw, oldOff, newLen)
|
|
92
|
+
then
|
|
93
|
+
dirtyN += 1
|
|
94
|
+
dirty[dirtyN] = i
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if dirtyN == 0 then
|
|
99
|
+
alloc (ch, 1)
|
|
100
|
+
buffer.writeu8 (ch.buff, ch.cursor, FLAG_UNCHANGED)
|
|
101
|
+
ch.cursor += 1
|
|
102
|
+
releaseScratch ()
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
alloc (ch, 1)
|
|
107
|
+
buffer.writeu8 (ch.buff, ch.cursor, FLAG_DELTA)
|
|
108
|
+
ch.cursor += 1
|
|
109
|
+
Varint.write (ch, dirtyN)
|
|
110
|
+
|
|
111
|
+
for j = 1, dirtyN do
|
|
112
|
+
local i = dirty[j]
|
|
113
|
+
local newOff = bounds[i]
|
|
114
|
+
local newLen = bounds[i + 1] - newOff
|
|
115
|
+
|
|
116
|
+
Varint.write (ch, i - 1)
|
|
117
|
+
alloc (ch, newLen)
|
|
118
|
+
buffer.copy (ch.buff, ch.cursor, scratch.buff, newOff, newLen)
|
|
119
|
+
ch.cursor += newLen
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
local rawBuf = buffer.create (scratchTotal)
|
|
124
|
+
buffer.copy (rawBuf, 0, scratch.buff, 0, scratchTotal)
|
|
125
|
+
|
|
126
|
+
table.freeze (bounds)
|
|
127
|
+
ch.deltas[deltaId] = { raw = rawBuf, bounds = bounds, len = len }
|
|
128
|
+
releaseScratch ()
|
|
129
|
+
end,
|
|
130
|
+
|
|
131
|
+
read = function (src: buffer, pos: number, refs: { Instance }?): ({ any }, number)
|
|
132
|
+
local flag = buffer.readu8 (src, pos)
|
|
133
|
+
local absPos = pos + 1
|
|
134
|
+
|
|
135
|
+
if flag == FLAG_UNCHANGED then
|
|
136
|
+
local cache = Baseline.getCache (deltaId)
|
|
137
|
+
return if cache then table.clone (cache) else {}, 1
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if flag == FLAG_FULL then
|
|
141
|
+
local len, lenBytes = Varint.read (src, absPos)
|
|
142
|
+
absPos += lenBytes
|
|
143
|
+
|
|
144
|
+
if maxCount and len > maxCount then
|
|
145
|
+
error (`[Lync] Array count {len} exceeds max {maxCount}`)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
local result = table.create (len)
|
|
149
|
+
|
|
150
|
+
if elemDRead and elemSize then
|
|
151
|
+
for i = 1, len do
|
|
152
|
+
result[i] = elemDRead (src, absPos)
|
|
153
|
+
absPos += elemSize
|
|
154
|
+
end
|
|
155
|
+
else
|
|
156
|
+
for i = 1, len do
|
|
157
|
+
local val, n = readElement (src, absPos, refs)
|
|
158
|
+
result[i] = val
|
|
159
|
+
absPos += n
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
Baseline.setCache (deltaId, result)
|
|
164
|
+
return result, absPos - pos
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
local cache = Baseline.getCache (deltaId) :: { any }?
|
|
168
|
+
local result = if cache then table.clone (cache) else {}
|
|
169
|
+
|
|
170
|
+
local dirtyN, dnBytes = Varint.read (src, absPos)
|
|
171
|
+
absPos += dnBytes
|
|
172
|
+
|
|
173
|
+
for _ = 1, dirtyN do
|
|
174
|
+
local idx, idxBytes = Varint.read (src, absPos)
|
|
175
|
+
absPos += idxBytes
|
|
176
|
+
|
|
177
|
+
if elemDRead and elemSize then
|
|
178
|
+
result[idx + 1] = elemDRead (src, absPos)
|
|
179
|
+
absPos += elemSize
|
|
180
|
+
else
|
|
181
|
+
local val, n = readElement (src, absPos, refs)
|
|
182
|
+
result[idx + 1] = val
|
|
183
|
+
absPos += n
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
Baseline.setCache (deltaId, result)
|
|
188
|
+
return result, absPos - pos
|
|
189
|
+
end,
|
|
190
|
+
})
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
function Array.array (element: Codec<any>, maxCount: number?): Codec<{ any }>
|
|
194
|
+
local elementSize = (element :: any)._size :: number?
|
|
195
|
+
local directWrite = (element :: any)._directWrite
|
|
196
|
+
local directRead = (element :: any)._directRead
|
|
197
|
+
|
|
198
|
+
if elementSize and directWrite and directRead then
|
|
199
|
+
return table.freeze ({
|
|
200
|
+
write = function (ch: ChannelState, value: { any }): ()
|
|
201
|
+
local len = #value
|
|
202
|
+
Varint.write (ch, len)
|
|
203
|
+
if len == 0 then
|
|
204
|
+
return
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
local totalBytes = len * elementSize
|
|
208
|
+
local c = ch.cursor
|
|
209
|
+
if c + totalBytes > ch.size then
|
|
210
|
+
alloc (ch, totalBytes)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
local b = ch.buff
|
|
214
|
+
for i = 1, len do
|
|
215
|
+
directWrite (b, c, value[i])
|
|
216
|
+
c += elementSize
|
|
217
|
+
end
|
|
218
|
+
ch.cursor = c
|
|
219
|
+
end,
|
|
220
|
+
read = function (src: buffer, pos: number, _refs: { Instance }?): ({ any }, number)
|
|
221
|
+
local len, lenBytes = Varint.read (src, pos)
|
|
222
|
+
|
|
223
|
+
if maxCount and len > maxCount then
|
|
224
|
+
error (`[Lync] Array count {len} exceeds max {maxCount}`)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
local result = table.create (len)
|
|
228
|
+
local c = pos + lenBytes
|
|
229
|
+
|
|
230
|
+
for i = 1, len do
|
|
231
|
+
result[i] = directRead (src, c)
|
|
232
|
+
c += elementSize
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
return result, c - pos
|
|
236
|
+
end,
|
|
237
|
+
})
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
local writeElement = element.write
|
|
241
|
+
local readElement = element.read
|
|
242
|
+
|
|
243
|
+
return table.freeze ({
|
|
244
|
+
write = function (ch: ChannelState, value: { any }): ()
|
|
245
|
+
local len = #value
|
|
246
|
+
Varint.write (ch, len)
|
|
247
|
+
if elementSize and len > 0 then
|
|
248
|
+
alloc (ch, len * elementSize)
|
|
249
|
+
end
|
|
250
|
+
for i = 1, len do
|
|
251
|
+
writeElement (ch, value[i])
|
|
252
|
+
end
|
|
253
|
+
end,
|
|
254
|
+
read = function (src: buffer, pos: number, refs: { Instance }?): ({ any }, number)
|
|
255
|
+
local len, lenBytes = Varint.read (src, pos)
|
|
256
|
+
|
|
257
|
+
if maxCount and len > maxCount then
|
|
258
|
+
error (`[Lync] Array count {len} exceeds max {maxCount}`)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
local result = table.create (len)
|
|
262
|
+
local absPos = pos + lenBytes
|
|
263
|
+
|
|
264
|
+
for i = 1, len do
|
|
265
|
+
local value, n = readElement (src, absPos, refs)
|
|
266
|
+
result[i] = value
|
|
267
|
+
absPos += n
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
return result, absPos - pos
|
|
271
|
+
end,
|
|
272
|
+
})
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
return table.freeze (Array)
|