@axpecter/lync 2.3.3 → 3.0.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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +302 -299
  3. package/Types.luau +215 -0
  4. package/api/Define.luau +154 -0
  5. package/api/Lifecycle.luau +119 -0
  6. package/api/Packet.luau +108 -0
  7. package/api/Query.luau +149 -0
  8. package/api/Set.luau +189 -0
  9. package/channel/Blocks.luau +124 -0
  10. package/channel/Group.luau +118 -0
  11. package/channel/Link.luau +135 -0
  12. package/channel/Outbox.luau +261 -0
  13. package/channel/Recipients.luau +129 -0
  14. package/channel/Transport.luau +138 -0
  15. package/codec/Base.luau +236 -0
  16. package/codec/Composites.luau +128 -0
  17. package/codec/Datatypes.luau +162 -0
  18. package/codec/Legality.luau +61 -0
  19. package/codec/Scalars.luau +72 -0
  20. package/codec/Text.luau +89 -0
  21. package/codec/init.luau +39 -0
  22. package/index.d.ts +285 -0
  23. package/init.luau +91 -0
  24. package/kernel/Bits.luau +16 -0
  25. package/kernel/Catalog.luau +121 -0
  26. package/kernel/Heap.luau +80 -0
  27. package/kernel/Listeners.luau +95 -0
  28. package/kernel/Log.luau +197 -0
  29. package/kernel/Tally.luau +128 -0
  30. package/kernel/Threads.luau +44 -0
  31. package/kernel/Wide.luau +267 -0
  32. package/package.json +15 -32
  33. package/runtime/Boundary.luau +180 -0
  34. package/runtime/Dispatch.luau +91 -0
  35. package/runtime/Handles.luau +114 -0
  36. package/runtime/Handshake.luau +90 -0
  37. package/runtime/Pending.luau +196 -0
  38. package/runtime/Router.luau +379 -0
  39. package/runtime/Session.luau +731 -0
  40. package/shape/Compile.luau +340 -0
  41. package/shape/Folds.luau +332 -0
  42. package/shape/Frames.luau +170 -0
  43. package/shape/Grid.luau +169 -0
  44. package/shape/Ir.luau +540 -0
  45. package/shape/Joins.luau +125 -0
  46. package/shape/Legality.luau +273 -0
  47. package/shape/Lower.luau +419 -0
  48. package/shape/Order.luau +64 -0
  49. package/shape/Regions.luau +113 -0
  50. package/shape/Rotation.luau +472 -0
  51. package/shape/Serial.luau +258 -0
  52. package/shape/Words.luau +89 -0
  53. package/shape/emit/Block.luau +453 -0
  54. package/shape/emit/Column.luau +338 -0
  55. package/shape/emit/Leaf.luau +462 -0
  56. package/shape/emit/Word.luau +234 -0
  57. package/shape/emit/init.luau +222 -0
  58. package/shape/init.luau +78 -0
  59. package/state/Apply.luau +330 -0
  60. package/state/Audience.luau +126 -0
  61. package/state/Catchup.luau +218 -0
  62. package/state/Coalesce.luau +43 -0
  63. package/state/Fieldset.luau +177 -0
  64. package/state/Newest.luau +339 -0
  65. package/state/Plan.luau +441 -0
  66. package/state/Sections.luau +468 -0
  67. package/state/Store.luau +188 -0
  68. package/state/Sync.luau +762 -0
  69. package/wire/Bytes.luau +118 -0
  70. package/wire/Clock.luau +37 -0
  71. package/wire/Protocol.luau +110 -0
  72. package/wire/Sequence.luau +40 -0
  73. package/wire/Varint.luau +124 -0
  74. package/src/Types.luau +0 -180
  75. package/src/api/Group.luau +0 -156
  76. package/src/api/Packet.luau +0 -317
  77. package/src/api/Query.luau +0 -338
  78. package/src/api/Scope.luau +0 -90
  79. package/src/api/Signal.luau +0 -193
  80. package/src/codec/Base.luau +0 -136
  81. package/src/codec/composite/Array.luau +0 -473
  82. package/src/codec/composite/Map.luau +0 -485
  83. package/src/codec/composite/Optional.luau +0 -54
  84. package/src/codec/composite/Shared.luau +0 -311
  85. package/src/codec/composite/Struct.luau +0 -494
  86. package/src/codec/composite/Tagged.luau +0 -103
  87. package/src/codec/composite/Tuple.luau +0 -143
  88. package/src/codec/datatype/Buffer.luau +0 -66
  89. package/src/codec/datatype/CFrame.luau +0 -109
  90. package/src/codec/datatype/Color.luau +0 -32
  91. package/src/codec/datatype/Instance.luau +0 -52
  92. package/src/codec/datatype/IntVector.luau +0 -39
  93. package/src/codec/datatype/NumberRange.luau +0 -39
  94. package/src/codec/datatype/Ray.luau +0 -36
  95. package/src/codec/datatype/Rect.luau +0 -31
  96. package/src/codec/datatype/Region.luau +0 -62
  97. package/src/codec/datatype/Sequence.luau +0 -184
  98. package/src/codec/datatype/String.luau +0 -94
  99. package/src/codec/datatype/UDim.luau +0 -46
  100. package/src/codec/datatype/Vector.luau +0 -130
  101. package/src/codec/meta/Auto.luau +0 -318
  102. package/src/codec/meta/Bitfield.luau +0 -160
  103. package/src/codec/meta/Custom.luau +0 -33
  104. package/src/codec/meta/DeltaScalar.luau +0 -390
  105. package/src/codec/meta/Enum.luau +0 -50
  106. package/src/codec/meta/Float.luau +0 -38
  107. package/src/codec/meta/Nothing.luau +0 -13
  108. package/src/codec/meta/Unknown.luau +0 -41
  109. package/src/codec/primitive/Bool.luau +0 -26
  110. package/src/codec/primitive/Float16.luau +0 -99
  111. package/src/codec/primitive/Int.luau +0 -59
  112. package/src/codec/primitive/Number.luau +0 -24
  113. package/src/codec/primitive/Signed.luau +0 -32
  114. package/src/codec/primitive/Varint.luau +0 -165
  115. package/src/codec/primitive/Zint.luau +0 -99
  116. package/src/index.d.ts +0 -423
  117. package/src/init.luau +0 -362
  118. package/src/internal/Baseline.luau +0 -57
  119. package/src/internal/Channel.luau +0 -484
  120. package/src/internal/Middleware.luau +0 -100
  121. package/src/internal/Pool.luau +0 -66
  122. package/src/internal/Registry.luau +0 -119
  123. package/src/internal/Transport.luau +0 -28
  124. package/src/transport/Bridge.luau +0 -110
  125. package/src/transport/Client.luau +0 -97
  126. package/src/transport/Gate.luau +0 -488
  127. package/src/transport/Reader.luau +0 -331
  128. package/src/transport/Server.luau +0 -233
  129. package/src/util/Array.luau +0 -18
  130. package/src/util/Buffer.luau +0 -90
  131. package/src/util/Constants.luau +0 -30
  132. package/src/util/Log.luau +0 -68
  133. package/src/util/Player.luau +0 -14
  134. package/src/util/Quantize.luau +0 -84
  135. package/src/util/Quat.luau +0 -124
@@ -1,494 +0,0 @@
1
- --!strict
2
- --!native
3
- -- struct() and deltaStruct(). Bool fields bit-pack into a tail block.
4
-
5
- local Base = require(script.Parent.Parent.Base)
6
- local Baseline = require(script.Parent.Parent.Parent.internal.Baseline)
7
- local Channel = require(script.Parent.Parent.Parent.internal.Channel)
8
- local Log = require(script.Parent.Parent.Parent.util.Log)
9
- local Shared = require(script.Parent.Parent.composite.Shared)
10
- local Types = require(script.Parent.Parent.Parent.Types)
11
-
12
- -- Private ----------------------------------------------------------------
13
-
14
- local alloc = Base.alloc
15
- local writeByte = Channel.writeByte
16
- local writeu8 = buffer.writeu8
17
- local writeu16 = buffer.writeu16
18
- local writeu32 = buffer.writeu32
19
- local readu8 = buffer.readu8
20
- local readu16 = buffer.readu16
21
- local readu32 = buffer.readu32
22
- local band = bit32.band
23
- local bor = bit32.bor
24
- local lshift = bit32.lshift
25
- local rshift = bit32.rshift
26
- local countrz = bit32.countrz
27
-
28
- -- 1/2/4-byte direct writes; 3-byte case splits into u16 + u8 (no native u24).
29
- local function writeBitmap(b: buffer, off: number, mask: number, bitmapBytes: number): ()
30
- if bitmapBytes == 1 then
31
- writeu8(b, off, mask)
32
- elseif bitmapBytes == 2 then
33
- writeu16(b, off, mask)
34
- elseif bitmapBytes == 4 then
35
- writeu32(b, off, mask)
36
- else
37
- writeu16(b, off, band(mask, 0xFFFF))
38
- writeu8(b, off + 2, band(rshift(mask, 16), 0xFF))
39
- end
40
- end
41
-
42
- local function readBitmap(b: buffer, off: number, bitmapBytes: number): number
43
- if bitmapBytes == 1 then
44
- return readu8(b, off)
45
- elseif bitmapBytes == 2 then
46
- return readu16(b, off)
47
- elseif bitmapBytes == 4 then
48
- return readu32(b, off)
49
- end
50
- return bor(readu16(b, off), lshift(readu8(b, off + 2), 16))
51
- end
52
-
53
- local extractFields = Shared.extractFields
54
- local packBools = Shared.packBools
55
- local unpackBools = Shared.unpackBools
56
- local rangeEqual = Shared.rangeEqual
57
- local snapshot = Shared.snapshot
58
- local refreshCache = Shared.refreshCache
59
- local acquireScratch = Shared.acquireScratch
60
- local releaseScratch = Shared.releaseScratch
61
- local allocDeltaId = Shared.allocDeltaId
62
- local DELTA_UNCHANGED = Shared.DELTA_UNCHANGED
63
- local DELTA_FULL_OFFSET = Shared.DELTA_FULL_OFFSET
64
- local DELTA_MULTI_OFFSET = Shared.DELTA_MULTI_OFFSET
65
-
66
- local function buildFrozenSchema(
67
- dataKeys: { string },
68
- boolKeys: { string },
69
- schema: { [string]: Types.InternalCodec<any> }
70
- ): { [string]: Types.InternalCodec<any> }
71
- local frozen: { [string]: Types.InternalCodec<any> } = {}
72
- for i = 1, #dataKeys do
73
- local k = dataKeys[i]
74
- frozen[k] = schema[k]
75
- end
76
- for i = 1, #boolKeys do
77
- local k = boolKeys[i]
78
- frozen[k] = schema[k]
79
- end
80
- return table.freeze(frozen)
81
- end
82
-
83
- -- Public -----------------------------------------------------------------
84
-
85
- local Struct = {}
86
-
87
- function Struct.struct(schema: { [string]: Types.InternalCodec<any> }): Types.InternalCodec<any>
88
- local dataKeys, dataCodecs, boolKeys = extractFields(schema)
89
- local dataCount = #dataKeys
90
- local boolCount = #boolKeys
91
- local boolBytes = Shared.boolBytes(boolCount)
92
-
93
- -- Single pass: detect all-direct fast-write path + propagate _hasUnknown / _hasDelta.
94
- local allDirect, fixedSize = true, 0
95
- local hasUnknown = false
96
- local hasDelta = false
97
- for i = 1, dataCount do
98
- local c = dataCodecs[i]
99
- if c._hasUnknown then
100
- hasUnknown = true
101
- end
102
- if Shared.containsDelta(c) then
103
- hasDelta = true
104
- end
105
- if allDirect then
106
- if c._size and c._directWrite and c._directRead then
107
- fixedSize += c._size
108
- else
109
- allDirect = false
110
- end
111
- end
112
- end
113
-
114
- local totalFixed = fixedSize + boolBytes
115
- local frozenSchema = buildFrozenSchema(dataKeys, boolKeys, schema)
116
-
117
- if allDirect and dataCount > 0 then
118
- local offsets = table.create(dataCount)
119
- local directWrites = table.create(dataCount)
120
- local directReads = table.create(dataCount)
121
- local runningOffset = 0
122
- for i = 1, dataCount do
123
- local c = dataCodecs[i]
124
- offsets[i] = runningOffset
125
- directWrites[i] = c._directWrite
126
- directReads[i] = c._directRead
127
- runningOffset += c._size :: number
128
- end
129
- table.freeze(offsets)
130
- table.freeze(directWrites)
131
- table.freeze(directReads)
132
-
133
- local codec: Types.InternalCodec<any> = {
134
- _size = totalFixed,
135
- _schema = frozenSchema,
136
-
137
- _directWrite = function(b: buffer, off: number, value: any): ()
138
- for i = 1, dataCount do
139
- directWrites[i](b, off + offsets[i], value[dataKeys[i]])
140
- end
141
- if boolCount == 0 then
142
- return
143
- end
144
-
145
- -- Inline bool packing to avoid the cursor-based packBools call.
146
- local boolOff = off + fixedSize
147
- local idx = 1
148
- for byteIdx = 0, boolBytes - 1 do
149
- local packed = 0
150
- local remaining = boolCount - idx + 1
151
- local limit = if remaining >= 8 then 8 else remaining
152
- for bit = 0, limit - 1 do
153
- if value[boolKeys[idx]] then
154
- packed = bor(packed, lshift(1, bit))
155
- end
156
- idx += 1
157
- end
158
- writeu8(b, boolOff + byteIdx, packed)
159
- end
160
- end,
161
-
162
- _directRead = function(b: buffer, off: number): any
163
- local result: { [string]: any } = {}
164
- for i = 1, dataCount do
165
- result[dataKeys[i]] = directReads[i](b, off + offsets[i])
166
- end
167
- if boolCount > 0 then
168
- unpackBools(b, off + fixedSize, boolKeys, boolCount, result, boolBytes)
169
- end
170
- return result
171
- end,
172
-
173
- write = function(ch: Types.ChannelState, value: any): ()
174
- local cursor = ch.cursor
175
- if cursor + totalFixed > ch.size then
176
- alloc(ch, totalFixed)
177
- end
178
- local b = ch.buff
179
- for i = 1, dataCount do
180
- directWrites[i](b, cursor + offsets[i], value[dataKeys[i]])
181
- end
182
- ch.cursor = cursor + fixedSize
183
- if boolCount > 0 then
184
- packBools(ch, value, boolKeys, boolCount, boolBytes)
185
- end
186
- end,
187
-
188
- read = function(src: buffer, pos: number, _refs: { Instance }?): (any, number)
189
- local result: { [string]: any } = {}
190
- for i = 1, dataCount do
191
- result[dataKeys[i]] = directReads[i](src, pos + offsets[i])
192
- end
193
- if boolCount > 0 then
194
- unpackBools(src, pos + fixedSize, boolKeys, boolCount, result, boolBytes)
195
- end
196
- return result, totalFixed
197
- end,
198
- }
199
- if hasUnknown then
200
- codec._hasUnknown = true
201
- end
202
- if hasDelta then
203
- codec._hasDelta = true
204
- end
205
- return table.freeze(codec)
206
- end
207
-
208
- local codec: Types.InternalCodec<any> = {
209
- _schema = frozenSchema,
210
-
211
- write = function(ch: Types.ChannelState, value: any): ()
212
- for i = 1, dataCount do
213
- dataCodecs[i].write(ch, value[dataKeys[i]])
214
- end
215
- if boolCount > 0 then
216
- packBools(ch, value, boolKeys, boolCount, boolBytes)
217
- end
218
- end,
219
-
220
- read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
221
- local result: { [string]: any } = {}
222
- local total = 0
223
- for i = 1, dataCount do
224
- local v, consumed = dataCodecs[i].read(src, pos + total, refs)
225
- result[dataKeys[i]] = v
226
- total += consumed
227
- end
228
- if boolCount > 0 then
229
- total += unpackBools(src, pos + total, boolKeys, boolCount, result, boolBytes)
230
- end
231
- return result, total
232
- end,
233
- }
234
- if hasUnknown then
235
- codec._hasUnknown = true
236
- end
237
- if hasDelta then
238
- codec._hasDelta = true
239
- end
240
- return table.freeze(codec)
241
- end
242
-
243
- --[[
244
- Per-field delta encoder. Splits a struct into segments (one per data
245
- field, plus one for the packed-bool block if any) and emits only changed
246
- segments. Wire flag byte:
247
- 0 UNCHANGED (reuse cache)
248
- [1 .. segCount] single segment k changed
249
- segCount + DELTA_FULL_OFFSET FULL payload
250
- segCount + DELTA_MULTI_OFFSET MULTI: bitmap + dirty segs in order
251
- ]]
252
- function Struct.deltaStruct(
253
- schema: { [string]: Types.InternalCodec<any> }
254
- ): Types.InternalCodec<any>
255
- local dataKeys, dataCodecs, boolKeys = extractFields(schema)
256
- local dataCount = #dataKeys
257
- local boolCount = #boolKeys
258
- local hasBoolSeg = boolCount > 0
259
- local segCount = dataCount + (if hasBoolSeg then 1 else 0)
260
- local FLAG_FULL = segCount + DELTA_FULL_OFFSET
261
- local FLAG_MULTI = segCount + DELTA_MULTI_OFFSET
262
- local boolSegIdx = segCount
263
-
264
- if FLAG_MULTI > 0xFF then
265
- Log.error(`too many segments ({segCount}); flag byte would overflow`)
266
- end
267
- if segCount > 32 then
268
- Log.error(`dirty bitmask is u32, segCount {segCount} exceeds 32`)
269
- end
270
-
271
- local deltaId = allocDeltaId()
272
- local innerStruct = Struct.struct(schema)
273
- -- Reuse innerStruct's frozen schema; avoids a second buildFrozenSchema.
274
- local frozenSchema = innerStruct._schema :: { [string]: Types.InternalCodec<any> }
275
-
276
- -- All-direct + fixed-size: segment offsets/lengths are statically known.
277
- local allDirect = dataCount > 0
278
- local fixedSize = 0
279
- for i = 1, dataCount do
280
- local c = dataCodecs[i]
281
- if not c._size or not c._directWrite or not c._directRead then
282
- allDirect = false
283
- break
284
- end
285
- fixedSize += c._size :: number
286
- end
287
-
288
- local boolBytes = Shared.boolBytes(boolCount)
289
- local bitmapBytes = Shared.boolBytes(segCount)
290
-
291
- local staticSegOff: { number }? = nil
292
- local staticSegLen: { number }? = nil
293
- if allDirect then
294
- local off = 0
295
- local segOff = table.create(segCount)
296
- local segLen = table.create(segCount)
297
- for i = 1, dataCount do
298
- segOff[i] = off
299
- segLen[i] = dataCodecs[i]._size :: number
300
- off += dataCodecs[i]._size :: number
301
- end
302
- if hasBoolSeg then
303
- segOff[boolSegIdx] = off
304
- segLen[boolSegIdx] = boolBytes
305
- end
306
- staticSegOff = table.freeze(segOff)
307
- staticSegLen = table.freeze(segLen)
308
- end
309
-
310
- -- Apply one segment's bytes onto `target`. Returns bytes consumed.
311
- local function applySegmentRead(
312
- target: { [string]: any },
313
- segIdx: number,
314
- src: buffer,
315
- pos: number,
316
- refs: { Instance }?
317
- ): number
318
- if hasBoolSeg and segIdx == boolSegIdx then
319
- return unpackBools(src, pos, boolKeys, boolCount, target, boolBytes)
320
- end
321
- local v, consumed = dataCodecs[segIdx].read(src, pos, refs)
322
- target[dataKeys[segIdx]] = v
323
- return consumed
324
- end
325
-
326
- -- Splice `src[srcOff..srcOff+len)` into the channel's main buffer.
327
- local function writeBytes(ch: Types.ChannelState, src: buffer, srcOff: number, len: number): ()
328
- if len == 0 then
329
- return
330
- end
331
- local cursor = ch.cursor
332
- if cursor + len > ch.size then
333
- alloc(ch, len)
334
- end
335
- buffer.copy(ch.buff, cursor, src, srcOff, len)
336
- ch.cursor = cursor + len
337
- end
338
-
339
- return table.freeze({
340
- _isDelta = true,
341
- _schema = frozenSchema,
342
-
343
- write = function(ch: Types.ChannelState, value: any): ()
344
- local scratch = acquireScratch()
345
- local segOff: { number }, segLen: { number }
346
-
347
- if staticSegOff then
348
- -- Bulk write via innerStruct, constant offsets.
349
- innerStruct.write(scratch, value)
350
- segOff = staticSegOff :: { number }
351
- segLen = staticSegLen :: { number }
352
- else
353
- segOff = table.create(segCount)
354
- segLen = table.create(segCount)
355
- local prev = 0
356
- for i = 1, dataCount do
357
- dataCodecs[i].write(scratch, value[dataKeys[i]])
358
- local cur = scratch.cursor
359
- segOff[i] = prev
360
- segLen[i] = cur - prev
361
- prev = cur
362
- end
363
- if hasBoolSeg then
364
- packBools(scratch, value, boolKeys, boolCount, boolBytes)
365
- segOff[boolSegIdx] = prev
366
- segLen[boolSegIdx] = scratch.cursor - prev
367
- end
368
- end
369
-
370
- local scratchLen = scratch.cursor
371
- local cache = ch.deltas[deltaId]
372
-
373
- if not cache then
374
- writeByte(ch, FLAG_FULL)
375
- writeBytes(ch, scratch.buff, 0, scratchLen)
376
- --[[
377
- Variable-size case stores fresh segOff/segLen by ref;
378
- static case stores the module-level frozen tables.
379
- ]]
380
- ch.deltas[deltaId] = {
381
- raw = snapshot(scratch.buff, scratchLen),
382
- len = scratchLen,
383
- segOff = segOff,
384
- segLen = segLen,
385
- } :: any
386
- releaseScratch()
387
- return
388
- end
389
-
390
- local cacheRaw = cache.raw
391
- local cacheOff = (cache :: any).segOff :: { number }
392
- local cacheLen = (cache :: any).segLen :: { number }
393
-
394
- local dirtyMask = 0
395
- local dirtyCount = 0
396
- for i = 1, segCount do
397
- local newLen = segLen[i]
398
- if
399
- newLen ~= cacheLen[i]
400
- or not rangeEqual(scratch.buff, segOff[i], cacheRaw, cacheOff[i], newLen)
401
- then
402
- dirtyMask = bor(dirtyMask, lshift(1, i - 1))
403
- dirtyCount += 1
404
- end
405
- end
406
-
407
- if dirtyCount == 0 then
408
- writeByte(ch, DELTA_UNCHANGED)
409
- releaseScratch()
410
- return
411
- end
412
-
413
- if dirtyCount == segCount then
414
- writeByte(ch, FLAG_FULL)
415
- writeBytes(ch, scratch.buff, 0, scratchLen)
416
- elseif dirtyCount == 1 then
417
- local segIdx = countrz(dirtyMask) + 1
418
- writeByte(ch, segIdx)
419
- writeBytes(ch, scratch.buff, segOff[segIdx], segLen[segIdx])
420
- else
421
- writeByte(ch, FLAG_MULTI)
422
- local cursor = ch.cursor
423
- if cursor + bitmapBytes > ch.size then
424
- alloc(ch, bitmapBytes)
425
- end
426
- writeBitmap(ch.buff, cursor, dirtyMask, bitmapBytes)
427
- ch.cursor = cursor + bitmapBytes
428
- for i = 1, segCount do
429
- if band(dirtyMask, lshift(1, i - 1)) ~= 0 then
430
- writeBytes(ch, scratch.buff, segOff[i], segLen[i])
431
- end
432
- end
433
- end
434
-
435
- refreshCache(cache, scratch.buff, scratchLen);
436
- (cache :: any).segOff = segOff;
437
- (cache :: any).segLen = segLen
438
- releaseScratch()
439
- end,
440
-
441
- read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
442
- local flag = readu8(src, pos)
443
-
444
- if flag == DELTA_UNCHANGED then
445
- local cached = Baseline.getCache(deltaId)
446
- if not cached then
447
- Log.error("UNCHANGED flag before any FULL frame; baseline missing")
448
- end
449
- return cached, 1
450
- end
451
-
452
- if flag == FLAG_FULL then
453
- local value, consumed = innerStruct.read(src, pos + 1, refs)
454
- Baseline.setCache(deltaId, value)
455
- return value, 1 + consumed
456
- end
457
-
458
- if flag <= segCount then
459
- local cached = Baseline.getCache(deltaId)
460
- if cached == nil then
461
- Log.error(
462
- `per-field update (seg {flag}) before any FULL frame; baseline missing`
463
- )
464
- end
465
- local newValue = table.clone(cached)
466
- local consumed = applySegmentRead(newValue, flag, src, pos + 1, refs)
467
- Baseline.setCache(deltaId, newValue)
468
- return newValue, 1 + consumed
469
- end
470
-
471
- if flag == FLAG_MULTI then
472
- local cached = Baseline.getCache(deltaId)
473
- if not cached then
474
- Log.error("multi-field update before any FULL frame")
475
- end
476
- local newValue = table.clone(cached)
477
- local mask = readBitmap(src, pos + 1, bitmapBytes)
478
- local total = 1 + bitmapBytes
479
- for i = 1, segCount do
480
- if band(mask, lshift(1, i - 1)) ~= 0 then
481
- local consumed = applySegmentRead(newValue, i, src, pos + total, refs)
482
- total += consumed
483
- end
484
- end
485
- Baseline.setCache(deltaId, newValue)
486
- return newValue, total
487
- end
488
-
489
- Log.error(`invalid delta flag {flag}`)
490
- end,
491
- }) :: Types.InternalCodec<any>
492
- end
493
-
494
- return table.freeze(Struct)
@@ -1,103 +0,0 @@
1
- --!strict
2
- --!native
3
- -- Discriminated union codec. u8 variant tag + variant payload.
4
-
5
- local Channel = require(script.Parent.Parent.Parent.internal.Channel)
6
- local Log = require(script.Parent.Parent.Parent.util.Log)
7
- local Shared = require(script.Parent.Parent.composite.Shared)
8
- local Types = require(script.Parent.Parent.Parent.Types)
9
-
10
- -- Private ----------------------------------------------------------------
11
-
12
- local writeByte = Channel.writeByte
13
- local readu8 = buffer.readu8
14
-
15
- -- Public -----------------------------------------------------------------
16
-
17
- local Tagged = {}
18
-
19
- function Tagged.define(
20
- tagField: string,
21
- variants: { [string]: Types.InternalCodec<any> }
22
- ): Types.InternalCodec<any>
23
- Log.assert(tagField ~= "", "tagField cannot be empty")
24
-
25
- -- Sort variant names so the wire-form tag id is stable across runs.
26
- local names: { string } = {}
27
- for name in variants do
28
- table.insert(names, name)
29
- end
30
- table.sort(names)
31
-
32
- local variantCount = #names
33
- Log.assert(variantCount > 0, "requires at least one variant")
34
- if variantCount > 256 then
35
- Log.error(`exceeds 256 variants ({variantCount})`)
36
- end
37
-
38
- local nameToTag: { [string]: number } = {}
39
- local tagToCodec = table.create(variantCount)
40
- local hasUnknown = false
41
- local hasDelta = false
42
-
43
- for i = 1, variantCount do
44
- local name = names[i]
45
- local codec = variants[name]
46
- nameToTag[name] = i - 1
47
- tagToCodec[i] = codec
48
- if codec._hasUnknown then
49
- hasUnknown = true
50
- end
51
- if Shared.containsDelta(codec) then
52
- hasDelta = true
53
- end
54
- end
55
-
56
- table.freeze(names)
57
- table.freeze(nameToTag)
58
- table.freeze(tagToCodec)
59
-
60
- local codec: Types.InternalCodec<any> = {
61
- _isTagged = true,
62
- _tagField = tagField,
63
- _variants = variants,
64
-
65
- write = function(ch: Types.ChannelState, value: any): ()
66
- local name = value[tagField]
67
- if name == nil then
68
- Log.error(`missing tagField "{tagField}"`)
69
- end
70
- local tag = nameToTag[name]
71
- if tag == nil then
72
- Log.error(`unknown variant "{name}"`)
73
- end
74
-
75
- writeByte(ch, tag)
76
- tagToCodec[tag + 1].write(ch, value)
77
- end,
78
-
79
- read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
80
- local tag = readu8(src, pos)
81
- local varCodec = tagToCodec[tag + 1]
82
- if not varCodec then
83
- Log.error(`unknown tag {tag}`)
84
- end
85
-
86
- local data, consumed = varCodec.read(src, pos + 1, refs)
87
- -- Re-attach the discriminator so callers can dispatch on it.
88
- if typeof(data) == "table" then
89
- data[tagField] = names[tag + 1]
90
- end
91
- return data, 1 + consumed
92
- end,
93
- }
94
- if hasUnknown then
95
- codec._hasUnknown = true
96
- end
97
- if hasDelta then
98
- codec._hasDelta = true
99
- end
100
- return table.freeze(codec)
101
- end
102
-
103
- return table.freeze(Tagged)