@axpecter/lync 2.1.1 → 2.2.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 +241 -349
- package/package.json +1 -1
- package/src/Types.luau +53 -13
- package/src/api/Group.luau +41 -51
- package/src/api/Packet.luau +145 -143
- package/src/api/Query.luau +204 -202
- package/src/api/Scope.luau +36 -38
- package/src/api/Signal.luau +68 -94
- package/src/codec/Base.luau +43 -23
- package/src/codec/composite/Array.luau +161 -152
- package/src/codec/composite/Map.luau +37 -53
- package/src/codec/composite/Optional.luau +15 -21
- package/src/codec/composite/Shared.luau +78 -41
- package/src/codec/composite/Struct.luau +64 -125
- package/src/codec/composite/Tagged.luau +15 -25
- package/src/codec/composite/Tuple.luau +15 -20
- package/src/codec/datatype/Buffer.luau +44 -51
- package/src/codec/datatype/CFrame.luau +72 -104
- package/src/codec/datatype/Color.luau +14 -10
- package/src/codec/datatype/Instance.luau +32 -42
- package/src/codec/datatype/IntVector.luau +24 -22
- package/src/codec/datatype/NumberRange.luau +21 -12
- package/src/codec/datatype/Ray.luau +13 -7
- package/src/codec/datatype/Rect.luau +13 -7
- package/src/codec/datatype/Region.luau +25 -22
- package/src/codec/datatype/Sequence.luau +144 -118
- package/src/codec/datatype/String.luau +29 -59
- package/src/codec/datatype/UDim.luau +29 -30
- package/src/codec/datatype/Vector.luau +89 -105
- package/src/codec/meta/Auto.luau +194 -246
- package/src/codec/meta/Bitfield.luau +37 -36
- package/src/codec/meta/Custom.luau +10 -10
- package/src/codec/meta/Enum.luau +8 -11
- package/src/codec/meta/Float.luau +16 -20
- package/src/codec/meta/Nothing.luau +2 -2
- package/src/codec/meta/Unknown.luau +22 -32
- package/src/codec/primitive/Bool.luau +9 -5
- package/src/codec/primitive/Float16.luau +13 -23
- package/src/codec/primitive/Int.luau +20 -28
- package/src/codec/primitive/Number.luau +6 -10
- package/src/codec/primitive/Signed.luau +32 -0
- package/src/codec/primitive/Varint.luau +59 -28
- package/src/index.d.ts +9 -3
- package/src/init.luau +118 -143
- package/src/internal/Baseline.luau +17 -18
- package/src/internal/Channel.luau +143 -212
- package/src/internal/Middleware.luau +37 -47
- package/src/internal/Pool.luau +10 -10
- package/src/internal/Registry.luau +38 -34
- package/src/internal/Transport.luau +28 -0
- package/src/internal/Util.luau +26 -0
- package/src/transport/Bridge.luau +32 -24
- package/src/transport/Client.luau +51 -53
- package/src/transport/Gate.luau +183 -113
- package/src/transport/Reader.luau +95 -66
- package/src/transport/Server.luau +130 -125
package/src/codec/meta/Auto.luau
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
-- Self-describing codec. u8 type tag + value payload.
|
|
4
4
|
|
|
5
5
|
local Base = require(script.Parent.Parent.Base)
|
|
6
|
-
local BoolC = require(script.Parent.Parent.primitive.Bool)
|
|
7
6
|
local BufferC = require(script.Parent.Parent.datatype.Buffer)
|
|
8
7
|
local CFrameC = require(script.Parent.Parent.datatype.CFrame)
|
|
8
|
+
local Channel = require(script.Parent.Parent.Parent.internal.Channel)
|
|
9
9
|
local ColorC = require(script.Parent.Parent.datatype.Color)
|
|
10
|
-
local Float16C = require(script.Parent.Parent.primitive.Float16)
|
|
11
10
|
local IVC = require(script.Parent.Parent.datatype.IntVector)
|
|
12
11
|
local NRC = require(script.Parent.Parent.datatype.NumberRange)
|
|
13
12
|
local NumberC = require(script.Parent.Parent.primitive.Number)
|
|
@@ -15,12 +14,13 @@ local RayC = require(script.Parent.Parent.datatype.Ray)
|
|
|
15
14
|
local RectC = require(script.Parent.Parent.datatype.Rect)
|
|
16
15
|
local RegionC = require(script.Parent.Parent.datatype.Region)
|
|
17
16
|
local SeqC = require(script.Parent.Parent.datatype.Sequence)
|
|
17
|
+
local Signed = require(script.Parent.Parent.primitive.Signed)
|
|
18
18
|
local Types = require(script.Parent.Parent.Parent.Types)
|
|
19
19
|
local UDimC = require(script.Parent.Parent.datatype.UDim)
|
|
20
20
|
local Varint = require(script.Parent.Parent.primitive.Varint)
|
|
21
21
|
local VecC = require(script.Parent.Parent.datatype.Vector)
|
|
22
22
|
|
|
23
|
-
-- Constants
|
|
23
|
+
-- Constants --------------------------------------------------------------
|
|
24
24
|
|
|
25
25
|
local TAG_NIL = 0
|
|
26
26
|
local TAG_BOOL = 1
|
|
@@ -51,68 +51,26 @@ local TAG_NUMSEQ = 25
|
|
|
51
51
|
local TAG_COLSEQ = 26
|
|
52
52
|
|
|
53
53
|
local INLINE_MAX = Varint.INLINE_MAX
|
|
54
|
+
local F32_SCRATCH = NumberC._f32Scratch
|
|
54
55
|
|
|
55
|
-
-- Private
|
|
56
|
+
-- Private ----------------------------------------------------------------
|
|
56
57
|
|
|
57
58
|
local alloc = Base.alloc
|
|
59
|
+
local writeByte = Channel.writeByte
|
|
58
60
|
local writeu8 = buffer.writeu8
|
|
59
61
|
local readu8 = buffer.readu8
|
|
60
62
|
local floor = math.floor
|
|
61
|
-
local
|
|
62
|
-
|
|
63
|
-
local F32_SCRATCH = NumberC._f32Scratch
|
|
63
|
+
local isnan = math.isnan
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
]]
|
|
69
|
-
local NUM_WRITE: { [number]: (buffer, number, number) -> () } = {
|
|
70
|
-
[TAG_U8] = buffer.writeu8,
|
|
71
|
-
[TAG_U16] = buffer.writeu16,
|
|
72
|
-
[TAG_U32] = buffer.writeu32,
|
|
73
|
-
[TAG_F32] = buffer.writef32,
|
|
74
|
-
[TAG_F64] = buffer.writef64,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
local NUM_SIZE: { [number]: number } = {
|
|
78
|
-
[TAG_U8] = 1,
|
|
79
|
-
[TAG_U16] = 2,
|
|
80
|
-
[TAG_U32] = 4,
|
|
81
|
-
[TAG_F32] = 4,
|
|
82
|
-
[TAG_F64] = 8,
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
-- writei8/i16/i32 are NOT FASTCALL, so we use writeu* with two's complement conversion
|
|
86
|
-
local function writeI8(b: buffer, off: number, v: number): ()
|
|
87
|
-
writeu8(b, off, if v < 0 then v + 0x100 else v)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
local function writeI16(b: buffer, off: number, v: number): ()
|
|
91
|
-
buffer.writeu16(b, off, if v < 0 then v + 0x10000 else v)
|
|
92
|
-
end
|
|
65
|
+
local writeI8 = Signed.writeI8
|
|
66
|
+
local writeI16 = Signed.writeI16
|
|
67
|
+
local writeI32 = Signed.writeI32
|
|
93
68
|
|
|
94
|
-
local function writeI32(b: buffer, off: number, v: number): ()
|
|
95
|
-
buffer.writeu32(b, off, if v < 0 then v + 0x100000000 else v)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
NUM_WRITE[TAG_I8] = writeI8
|
|
99
|
-
NUM_WRITE[TAG_I16] = writeI16
|
|
100
|
-
NUM_WRITE[TAG_I32] = writeI32
|
|
101
|
-
NUM_SIZE[TAG_I8] = 1
|
|
102
|
-
NUM_SIZE[TAG_I16] = 2
|
|
103
|
-
NUM_SIZE[TAG_I32] = 4
|
|
104
|
-
|
|
105
|
-
table.freeze(NUM_WRITE)
|
|
106
|
-
table.freeze(NUM_SIZE)
|
|
107
|
-
|
|
108
|
-
-- Selects the smallest integer/float tag for a number value
|
|
109
69
|
local function selectNumberTag(value: number): number
|
|
110
|
-
|
|
111
|
-
if value ~= value then
|
|
70
|
+
if isnan(value) then
|
|
112
71
|
return TAG_F64
|
|
113
72
|
end
|
|
114
73
|
|
|
115
|
-
-- Integer path
|
|
116
74
|
if floor(value) == value then
|
|
117
75
|
if value >= 0 then
|
|
118
76
|
if value <= 0xFF then
|
|
@@ -137,23 +95,85 @@ local function selectNumberTag(value: number): number
|
|
|
137
95
|
end
|
|
138
96
|
end
|
|
139
97
|
|
|
140
|
-
--
|
|
98
|
+
-- Roblox is single-threaded so a module scratch cannot be aliased.
|
|
141
99
|
buffer.writef32(F32_SCRATCH, 0, value)
|
|
142
100
|
if buffer.readf32(F32_SCRATCH, 0) == value then
|
|
143
101
|
return TAG_F32
|
|
144
102
|
end
|
|
145
|
-
|
|
146
103
|
return TAG_F64
|
|
147
104
|
end
|
|
148
105
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
106
|
+
local function numberSize(tag: number): number
|
|
107
|
+
if tag == TAG_U8 or tag == TAG_I8 then
|
|
108
|
+
return 1
|
|
109
|
+
end
|
|
110
|
+
if tag == TAG_U16 or tag == TAG_I16 then
|
|
111
|
+
return 2
|
|
112
|
+
end
|
|
113
|
+
if tag == TAG_U32 or tag == TAG_I32 or tag == TAG_F32 then
|
|
114
|
+
return 4
|
|
115
|
+
end
|
|
116
|
+
return 8
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
local function writeNumber(b: buffer, off: number, tag: number, value: number): ()
|
|
120
|
+
if tag == TAG_U8 then
|
|
121
|
+
buffer.writeu8(b, off, value)
|
|
122
|
+
return
|
|
123
|
+
end
|
|
124
|
+
if tag == TAG_U16 then
|
|
125
|
+
buffer.writeu16(b, off, value)
|
|
126
|
+
return
|
|
127
|
+
end
|
|
128
|
+
if tag == TAG_U32 then
|
|
129
|
+
buffer.writeu32(b, off, value)
|
|
130
|
+
return
|
|
131
|
+
end
|
|
132
|
+
if tag == TAG_I8 then
|
|
133
|
+
writeI8(b, off, value)
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
if tag == TAG_I16 then
|
|
137
|
+
writeI16(b, off, value)
|
|
138
|
+
return
|
|
139
|
+
end
|
|
140
|
+
if tag == TAG_I32 then
|
|
141
|
+
writeI32(b, off, value)
|
|
142
|
+
return
|
|
143
|
+
end
|
|
144
|
+
if tag == TAG_F32 then
|
|
145
|
+
buffer.writef32(b, off, value)
|
|
146
|
+
return
|
|
147
|
+
end
|
|
148
|
+
buffer.writef64(b, off, value)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
local function readNumber(b: buffer, off: number, tag: number): number
|
|
152
|
+
if tag == TAG_U8 then
|
|
153
|
+
return buffer.readu8(b, off)
|
|
154
|
+
end
|
|
155
|
+
if tag == TAG_U16 then
|
|
156
|
+
return buffer.readu16(b, off)
|
|
157
|
+
end
|
|
158
|
+
if tag == TAG_U32 then
|
|
159
|
+
return buffer.readu32(b, off)
|
|
160
|
+
end
|
|
161
|
+
if tag == TAG_I8 then
|
|
162
|
+
return buffer.readi8(b, off)
|
|
163
|
+
end
|
|
164
|
+
if tag == TAG_I16 then
|
|
165
|
+
return buffer.readi16(b, off)
|
|
166
|
+
end
|
|
167
|
+
if tag == TAG_I32 then
|
|
168
|
+
return buffer.readi32(b, off)
|
|
169
|
+
end
|
|
170
|
+
if tag == TAG_F32 then
|
|
171
|
+
return buffer.readf32(b, off)
|
|
172
|
+
end
|
|
173
|
+
return buffer.readf64(b, off)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
type TypeEntry = { tag: number, codec: Types.InternalCodec<any> }
|
|
157
177
|
|
|
158
178
|
local TYPE_DISPATCH: { [string]: TypeEntry } = table.freeze({
|
|
159
179
|
Vector2 = { tag = TAG_VEC2, codec = VecC.vec2 },
|
|
@@ -171,9 +191,8 @@ local TYPE_DISPATCH: { [string]: TypeEntry } = table.freeze({
|
|
|
171
191
|
Ray = { tag = TAG_RAY, codec = RayC.ray },
|
|
172
192
|
NumberSequence = { tag = TAG_NUMSEQ, codec = SeqC.numberSequence },
|
|
173
193
|
ColorSequence = { tag = TAG_COLSEQ, codec = SeqC.colorSequence },
|
|
174
|
-
}
|
|
194
|
+
})
|
|
175
195
|
|
|
176
|
-
-- Read dispatch: tag → codec
|
|
177
196
|
local READ_DISPATCH: { [number]: Types.InternalCodec<any> } = table.freeze({
|
|
178
197
|
[TAG_VEC2] = VecC.vec2,
|
|
179
198
|
[TAG_VEC3] = VecC.vec3,
|
|
@@ -190,213 +209,142 @@ local READ_DISPATCH: { [number]: Types.InternalCodec<any> } = table.freeze({
|
|
|
190
209
|
[TAG_RAY] = RayC.ray,
|
|
191
210
|
[TAG_NUMSEQ] = SeqC.numberSequence,
|
|
192
211
|
[TAG_COLSEQ] = SeqC.colorSequence,
|
|
193
|
-
} :: any)
|
|
194
|
-
|
|
195
|
-
-- Numeric read helpers
|
|
196
|
-
local function readI8(b: buffer, off: number): number
|
|
197
|
-
local raw = readu8(b, off)
|
|
198
|
-
return if raw >= 0x80 then raw - 0x100 else raw
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
local function readI16(b: buffer, off: number): number
|
|
202
|
-
local raw = buffer.readu16(b, off)
|
|
203
|
-
return if raw >= 0x8000 then raw - 0x10000 else raw
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
local function readI32(b: buffer, off: number): number
|
|
207
|
-
local raw = buffer.readu32(b, off)
|
|
208
|
-
return if raw >= 0x80000000 then raw - 0x100000000 else raw
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
local NUM_READ: { [number]: (buffer, number) -> number } = table.freeze({
|
|
212
|
-
[TAG_U8] = buffer.readu8,
|
|
213
|
-
[TAG_U16] = buffer.readu16,
|
|
214
|
-
[TAG_U32] = buffer.readu32,
|
|
215
|
-
[TAG_I8] = readI8,
|
|
216
|
-
[TAG_I16] = readI16,
|
|
217
|
-
[TAG_I32] = readI32,
|
|
218
|
-
[TAG_F32] = buffer.readf32,
|
|
219
|
-
[TAG_F64] = buffer.readf64,
|
|
220
212
|
})
|
|
221
213
|
|
|
222
|
-
|
|
214
|
+
local function writeAuto(ch: Types.ChannelState, value: any): ()
|
|
215
|
+
if value == nil then
|
|
216
|
+
writeByte(ch, TAG_NIL)
|
|
217
|
+
return
|
|
218
|
+
end
|
|
223
219
|
|
|
224
|
-
local
|
|
220
|
+
local t = typeof(value)
|
|
225
221
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if
|
|
229
|
-
|
|
230
|
-
if cursor + 1 > ch.size then
|
|
231
|
-
alloc(ch, 1)
|
|
232
|
-
end
|
|
233
|
-
writeu8(ch.buff, cursor, TAG_NIL)
|
|
234
|
-
ch.cursor = cursor + 1
|
|
235
|
-
return
|
|
222
|
+
if t == "boolean" then
|
|
223
|
+
local cursor = ch.cursor
|
|
224
|
+
if cursor + 2 > ch.size then
|
|
225
|
+
alloc(ch, 2)
|
|
236
226
|
end
|
|
227
|
+
local b = ch.buff
|
|
228
|
+
writeu8(b, cursor, TAG_BOOL)
|
|
229
|
+
writeu8(b, cursor + 1, if value then 1 else 0)
|
|
230
|
+
ch.cursor = cursor + 2
|
|
231
|
+
return
|
|
232
|
+
end
|
|
237
233
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
end
|
|
245
|
-
local b = ch.buff
|
|
246
|
-
writeu8(b, cursor, TAG_BOOL)
|
|
247
|
-
writeu8(b, cursor + 1, if value then 1 else 0)
|
|
248
|
-
ch.cursor = cursor + 2
|
|
249
|
-
return
|
|
234
|
+
if t == "number" then
|
|
235
|
+
local tag = selectNumberTag(value)
|
|
236
|
+
local totalSize = 1 + numberSize(tag)
|
|
237
|
+
local cursor = ch.cursor
|
|
238
|
+
if cursor + totalSize > ch.size then
|
|
239
|
+
alloc(ch, totalSize)
|
|
250
240
|
end
|
|
241
|
+
local b = ch.buff
|
|
242
|
+
writeu8(b, cursor, tag)
|
|
243
|
+
writeNumber(b, cursor + 1, tag, value)
|
|
244
|
+
ch.cursor = cursor + totalSize
|
|
245
|
+
return
|
|
246
|
+
end
|
|
251
247
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
local payloadSize = NUM_SIZE[tag]
|
|
255
|
-
local totalSize = 1 + payloadSize
|
|
256
|
-
local cursor = ch.cursor
|
|
257
|
-
if cursor + totalSize > ch.size then
|
|
258
|
-
alloc(ch, totalSize)
|
|
259
|
-
end
|
|
260
|
-
local b = ch.buff
|
|
261
|
-
writeu8(b, cursor, tag)
|
|
262
|
-
NUM_WRITE[tag](b, cursor + 1, value)
|
|
263
|
-
ch.cursor = cursor + totalSize
|
|
264
|
-
return
|
|
265
|
-
end
|
|
248
|
+
if t == "string" then
|
|
249
|
+
writeByte(ch, TAG_STRING)
|
|
266
250
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
writeu8(ch.buff, cursor, TAG_STRING)
|
|
273
|
-
ch.cursor = cursor + 1
|
|
274
|
-
-- Inline string write (same as String codec)
|
|
275
|
-
local len = #value
|
|
276
|
-
cursor = ch.cursor
|
|
277
|
-
if len <= INLINE_MAX then
|
|
278
|
-
if cursor + 1 + len > ch.size then
|
|
279
|
-
alloc(ch, 1 + len)
|
|
280
|
-
end
|
|
281
|
-
local b = ch.buff
|
|
282
|
-
writeu8(b, cursor, len)
|
|
283
|
-
if len > 0 then
|
|
284
|
-
buffer.writestring(b, cursor + 1, value)
|
|
285
|
-
end
|
|
286
|
-
ch.cursor = cursor + 1 + len
|
|
287
|
-
else
|
|
288
|
-
Varint.write(ch, len)
|
|
289
|
-
cursor = ch.cursor
|
|
290
|
-
if cursor + len > ch.size then
|
|
291
|
-
alloc(ch, len)
|
|
292
|
-
end
|
|
293
|
-
buffer.writestring(ch.buff, cursor, value)
|
|
294
|
-
ch.cursor = cursor + len
|
|
251
|
+
local len = #value
|
|
252
|
+
local cursor = ch.cursor
|
|
253
|
+
if len <= INLINE_MAX then
|
|
254
|
+
if cursor + 1 + len > ch.size then
|
|
255
|
+
alloc(ch, 1 + len)
|
|
295
256
|
end
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
local cursor = ch.cursor
|
|
301
|
-
if cursor + 1 > ch.size then
|
|
302
|
-
alloc(ch, 1)
|
|
257
|
+
local b = ch.buff
|
|
258
|
+
writeu8(b, cursor, len)
|
|
259
|
+
if len > 0 then
|
|
260
|
+
buffer.writestring(b, cursor + 1, value)
|
|
303
261
|
end
|
|
304
|
-
|
|
305
|
-
ch.cursor = cursor + 1
|
|
306
|
-
BufferC.buff.write(ch, value)
|
|
262
|
+
ch.cursor = cursor + 1 + len
|
|
307
263
|
return
|
|
308
264
|
end
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
local codec = entry.codec
|
|
314
|
-
local size = codec._size
|
|
315
|
-
local dw = codec._directWrite
|
|
316
|
-
|
|
317
|
-
if size and dw then
|
|
318
|
-
-- Fast path: direct write
|
|
319
|
-
local totalSize = 1 + size
|
|
320
|
-
local cursor = ch.cursor
|
|
321
|
-
if cursor + totalSize > ch.size then
|
|
322
|
-
alloc(ch, totalSize)
|
|
323
|
-
end
|
|
324
|
-
local b = ch.buff
|
|
325
|
-
writeu8(b, cursor, entry.tag)
|
|
326
|
-
dw(b, cursor + 1, value)
|
|
327
|
-
ch.cursor = cursor + totalSize
|
|
328
|
-
else
|
|
329
|
-
-- Generic path
|
|
330
|
-
local cursor = ch.cursor
|
|
331
|
-
if cursor + 1 > ch.size then
|
|
332
|
-
alloc(ch, 1)
|
|
333
|
-
end
|
|
334
|
-
writeu8(ch.buff, cursor, entry.tag)
|
|
335
|
-
ch.cursor = cursor + 1
|
|
336
|
-
codec.write(ch, value)
|
|
337
|
-
end
|
|
338
|
-
return
|
|
265
|
+
Varint.write(ch, len)
|
|
266
|
+
cursor = ch.cursor
|
|
267
|
+
if cursor + len > ch.size then
|
|
268
|
+
alloc(ch, len)
|
|
339
269
|
end
|
|
270
|
+
buffer.writestring(ch.buff, cursor, value)
|
|
271
|
+
ch.cursor = cursor + len
|
|
272
|
+
return
|
|
273
|
+
end
|
|
340
274
|
|
|
341
|
-
|
|
342
|
-
|
|
275
|
+
if t == "buffer" then
|
|
276
|
+
writeByte(ch, TAG_BUFFER)
|
|
277
|
+
BufferC.buff.write(ch, value)
|
|
278
|
+
return
|
|
279
|
+
end
|
|
343
280
|
|
|
344
|
-
|
|
345
|
-
|
|
281
|
+
local entry = TYPE_DISPATCH[t]
|
|
282
|
+
if not entry then
|
|
283
|
+
error(`[Lync] Auto.write: unsupported type "{t}"`)
|
|
284
|
+
end
|
|
346
285
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
286
|
+
local codec = entry.codec
|
|
287
|
+
local size = codec._size
|
|
288
|
+
local dw = codec._directWrite
|
|
289
|
+
if size and dw then
|
|
290
|
+
local totalSize = 1 + size
|
|
291
|
+
local cursor = ch.cursor
|
|
292
|
+
if cursor + totalSize > ch.size then
|
|
293
|
+
alloc(ch, totalSize)
|
|
350
294
|
end
|
|
295
|
+
local b = ch.buff
|
|
296
|
+
writeu8(b, cursor, entry.tag)
|
|
297
|
+
dw(b, cursor + 1, value)
|
|
298
|
+
ch.cursor = cursor + totalSize
|
|
299
|
+
return
|
|
300
|
+
end
|
|
351
301
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
end
|
|
302
|
+
writeByte(ch, entry.tag)
|
|
303
|
+
codec.write(ch, value)
|
|
304
|
+
end
|
|
356
305
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if numRead then
|
|
360
|
-
local payloadSize = NUM_SIZE[tag]
|
|
361
|
-
return numRead(src, pos + 1), 1 + payloadSize
|
|
362
|
-
end
|
|
306
|
+
local function readAuto(src: buffer, pos: number, refs: { Instance }?): (any, number)
|
|
307
|
+
local tag = readu8(src, pos)
|
|
363
308
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if b0 <= INLINE_MAX then
|
|
371
|
-
len = b0
|
|
372
|
-
lenBytes = 1
|
|
373
|
-
else
|
|
374
|
-
len, lenBytes = Varint.read(src, pos + 1)
|
|
375
|
-
end
|
|
309
|
+
if tag == TAG_NIL then
|
|
310
|
+
return nil, 1
|
|
311
|
+
end
|
|
312
|
+
if tag == TAG_BOOL then
|
|
313
|
+
return readu8(src, pos + 1) ~= 0, 2
|
|
314
|
+
end
|
|
376
315
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
316
|
+
if tag >= TAG_U8 and tag <= TAG_F64 then
|
|
317
|
+
return readNumber(src, pos + 1, tag), 1 + numberSize(tag)
|
|
318
|
+
end
|
|
380
319
|
|
|
381
|
-
|
|
382
|
-
|
|
320
|
+
if tag == TAG_STRING then
|
|
321
|
+
local len, lenBytes = Varint.readLengthPrefix(src, pos + 1)
|
|
322
|
+
if len == 0 then
|
|
323
|
+
return "", 1 + lenBytes
|
|
383
324
|
end
|
|
325
|
+
return buffer.readstring(src, pos + 1 + lenBytes, len), 1 + lenBytes + len
|
|
326
|
+
end
|
|
384
327
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
end
|
|
328
|
+
if tag == TAG_BUFFER then
|
|
329
|
+
local value, consumed = BufferC.buff.read(src, pos + 1, refs)
|
|
330
|
+
return value, 1 + consumed
|
|
331
|
+
end
|
|
390
332
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
333
|
+
local codec = READ_DISPATCH[tag]
|
|
334
|
+
if not codec then
|
|
335
|
+
error(`[Lync] Auto.read: unknown tag {tag}`)
|
|
336
|
+
end
|
|
337
|
+
local value, consumed = codec.read(src, pos + 1, refs)
|
|
338
|
+
return value, 1 + consumed
|
|
339
|
+
end
|
|
397
340
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
341
|
+
-- Public -----------------------------------------------------------------
|
|
342
|
+
|
|
343
|
+
local AutoModule = {}
|
|
344
|
+
|
|
345
|
+
AutoModule.auto = table.freeze({
|
|
346
|
+
write = writeAuto,
|
|
347
|
+
read = readAuto,
|
|
348
|
+
})
|
|
401
349
|
|
|
402
350
|
return table.freeze(AutoModule)
|
|
@@ -1,38 +1,54 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--!native
|
|
3
|
-
-- Sub-byte packing. 1 to 32 bits across bool/uint/int fields.
|
|
3
|
+
-- Sub-byte packing. 1 to 32 bits across bool / uint / int fields.
|
|
4
4
|
|
|
5
5
|
local Base = require(script.Parent.Parent.Base)
|
|
6
|
+
local Types = require(script.Parent.Parent.Parent.Types)
|
|
6
7
|
|
|
7
|
-
--
|
|
8
|
+
-- Constants --------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
local TYPE_BOOL = 0
|
|
11
|
+
local TYPE_UINT = 1
|
|
12
|
+
local TYPE_INT = 2
|
|
13
|
+
|
|
14
|
+
-- Private ----------------------------------------------------------------
|
|
8
15
|
|
|
9
16
|
local band = bit32.band
|
|
10
17
|
local bor = bit32.bor
|
|
11
18
|
local lshift = bit32.lshift
|
|
12
19
|
local rshift = bit32.rshift
|
|
13
20
|
|
|
14
|
-
--
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
--[[
|
|
22
|
+
Width-aware mask: bit32.lshift(1, 32) returns 0, so 32-bit fields
|
|
23
|
+
need the all-ones mask explicitly. Sign-extension constants for int
|
|
24
|
+
fields use 2^(width-1) and 2^width via numeric exponentiation so
|
|
25
|
+
width=32 still produces 0x80000000 / 0x100000000 correctly.
|
|
26
|
+
]]
|
|
27
|
+
local function widthMask(width: number): number
|
|
28
|
+
if width >= 32 then
|
|
29
|
+
return 0xFFFFFFFF
|
|
30
|
+
end
|
|
31
|
+
return lshift(1, width) - 1
|
|
32
|
+
end
|
|
18
33
|
|
|
19
|
-
-- Public
|
|
34
|
+
-- Public -----------------------------------------------------------------
|
|
20
35
|
|
|
21
36
|
local Bitfield = {}
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
export type FieldSpec = { type: "bool" | "uint" | "int", width: number? }
|
|
39
|
+
|
|
40
|
+
function Bitfield.define(schema: { [string]: FieldSpec }): Types.InternalCodec<any>
|
|
41
|
+
local keys: { string } = {}
|
|
26
42
|
for key in schema do
|
|
27
43
|
table.insert(keys, key)
|
|
28
44
|
end
|
|
29
45
|
table.sort(keys)
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
local fieldCount = #keys
|
|
48
|
+
if fieldCount == 0 then
|
|
32
49
|
error("[Lync] Lync.bitfield: requires at least one field")
|
|
33
50
|
end
|
|
34
51
|
|
|
35
|
-
local fieldCount = #keys
|
|
36
52
|
local fieldKeys = table.create(fieldCount)
|
|
37
53
|
local fieldTypes = table.create(fieldCount)
|
|
38
54
|
local fieldOffsets = table.create(fieldCount)
|
|
@@ -59,7 +75,7 @@ function Bitfield.define(schema: { [string]: { type: string, width: number? } })
|
|
|
59
75
|
error(`[Lync] Lync.bitfield: field "{key}" uint width must be 1-32`)
|
|
60
76
|
end
|
|
61
77
|
fieldTypes[i] = TYPE_UINT
|
|
62
|
-
fieldMasks[i] =
|
|
78
|
+
fieldMasks[i] = widthMask(width)
|
|
63
79
|
fieldSignBit[i] = 0
|
|
64
80
|
fieldSignExt[i] = 0
|
|
65
81
|
totalBits += width
|
|
@@ -69,12 +85,12 @@ function Bitfield.define(schema: { [string]: { type: string, width: number? } })
|
|
|
69
85
|
error(`[Lync] Lync.bitfield: field "{key}" int width must be 2-32`)
|
|
70
86
|
end
|
|
71
87
|
fieldTypes[i] = TYPE_INT
|
|
72
|
-
fieldMasks[i] =
|
|
73
|
-
fieldSignBit[i] =
|
|
74
|
-
fieldSignExt[i] =
|
|
88
|
+
fieldMasks[i] = widthMask(width)
|
|
89
|
+
fieldSignBit[i] = 2 ^ (width - 1)
|
|
90
|
+
fieldSignExt[i] = 2 ^ width
|
|
75
91
|
totalBits += width
|
|
76
92
|
else
|
|
77
|
-
error(`[Lync] Lync.bitfield: unknown
|
|
93
|
+
error(`[Lync] Lync.bitfield: field "{key}" has unknown type "{spec.type}"`)
|
|
78
94
|
end
|
|
79
95
|
end
|
|
80
96
|
|
|
@@ -82,26 +98,17 @@ function Bitfield.define(schema: { [string]: { type: string, width: number? } })
|
|
|
82
98
|
error(`[Lync] Lync.bitfield: total exceeds 32 bits ({totalBits})`)
|
|
83
99
|
end
|
|
84
100
|
|
|
85
|
-
-- Determine wire size
|
|
86
101
|
local wireBytes: number
|
|
87
102
|
local wfn: (buffer, number, number) -> ()
|
|
88
103
|
local rfn: (buffer, number) -> number
|
|
89
|
-
|
|
90
104
|
if totalBits <= 8 then
|
|
91
|
-
wireBytes = 1
|
|
92
|
-
wfn = buffer.writeu8
|
|
93
|
-
rfn = buffer.readu8
|
|
105
|
+
wireBytes, wfn, rfn = 1, buffer.writeu8, buffer.readu8
|
|
94
106
|
elseif totalBits <= 16 then
|
|
95
|
-
wireBytes = 2
|
|
96
|
-
wfn = buffer.writeu16
|
|
97
|
-
rfn = buffer.readu16
|
|
107
|
+
wireBytes, wfn, rfn = 2, buffer.writeu16, buffer.readu16
|
|
98
108
|
else
|
|
99
|
-
wireBytes = 4
|
|
100
|
-
wfn = buffer.writeu32
|
|
101
|
-
rfn = buffer.readu32
|
|
109
|
+
wireBytes, wfn, rfn = 4, buffer.writeu32, buffer.readu32
|
|
102
110
|
end
|
|
103
111
|
|
|
104
|
-
-- Freeze all descriptor arrays
|
|
105
112
|
table.freeze(fieldKeys)
|
|
106
113
|
table.freeze(fieldTypes)
|
|
107
114
|
table.freeze(fieldOffsets)
|
|
@@ -125,22 +132,16 @@ function Bitfield.define(schema: { [string]: { type: string, width: number? } })
|
|
|
125
132
|
end, function(b: buffer, off: number): any
|
|
126
133
|
local packed = rfn(b, off)
|
|
127
134
|
local result: { [string]: any } = {}
|
|
128
|
-
|
|
129
135
|
for i = 1, fieldCount do
|
|
130
136
|
local raw = band(rshift(packed, fieldOffsets[i]), fieldMasks[i])
|
|
131
137
|
if fieldTypes[i] == TYPE_BOOL then
|
|
132
138
|
result[fieldKeys[i]] = raw ~= 0
|
|
133
139
|
elseif fieldTypes[i] == TYPE_INT then
|
|
134
|
-
if raw >= fieldSignBit[i] then
|
|
135
|
-
result[fieldKeys[i]] = raw - fieldSignExt[i]
|
|
136
|
-
else
|
|
137
|
-
result[fieldKeys[i]] = raw
|
|
138
|
-
end
|
|
140
|
+
result[fieldKeys[i]] = if raw >= fieldSignBit[i] then raw - fieldSignExt[i] else raw
|
|
139
141
|
else
|
|
140
142
|
result[fieldKeys[i]] = raw
|
|
141
143
|
end
|
|
142
144
|
end
|
|
143
|
-
|
|
144
145
|
return result
|
|
145
146
|
end)
|
|
146
147
|
end
|