@axpecter/lync 2.0.0 → 2.1.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 +475 -426
- package/package.json +1 -1
- package/src/Types.luau +63 -31
- package/src/api/Group.luau +101 -106
- package/src/api/Packet.luau +187 -186
- package/src/api/Query.luau +223 -284
- package/src/api/Scope.luau +46 -57
- package/src/api/Signal.luau +104 -137
- package/src/codec/Base.luau +69 -20
- package/src/codec/composite/Array.luau +179 -270
- package/src/codec/composite/Map.luau +97 -347
- package/src/codec/composite/Optional.luau +27 -24
- package/src/codec/composite/Shared.luau +96 -65
- package/src/codec/composite/Struct.luau +200 -360
- package/src/codec/composite/Tagged.luau +62 -187
- package/src/codec/composite/Tuple.luau +79 -103
- package/src/codec/datatype/Buffer.luau +49 -21
- package/src/codec/datatype/CFrame.luau +207 -30
- package/src/codec/datatype/Color.luau +21 -11
- package/src/codec/datatype/Instance.luau +28 -21
- package/src/codec/datatype/IntVector.luau +33 -21
- package/src/codec/datatype/NumberRange.luau +19 -10
- package/src/codec/datatype/Ray.luau +26 -22
- package/src/codec/datatype/Rect.luau +20 -16
- package/src/codec/datatype/Region.luau +51 -45
- package/src/codec/datatype/Sequence.luau +64 -56
- package/src/codec/datatype/String.luau +89 -56
- package/src/codec/datatype/UDim.luau +40 -22
- package/src/codec/datatype/Vector.luau +181 -17
- package/src/codec/meta/Auto.luau +295 -253
- package/src/codec/meta/Bitfield.luau +104 -148
- package/src/codec/meta/Custom.luau +8 -4
- package/src/codec/meta/Enum.luau +29 -57
- package/src/codec/meta/Float.luau +64 -0
- package/src/codec/meta/Nothing.luau +9 -5
- package/src/codec/meta/Unknown.luau +44 -36
- package/src/codec/primitive/Bool.luau +16 -26
- package/src/codec/primitive/Float16.luau +58 -64
- package/src/codec/primitive/Int.luau +68 -0
- package/src/codec/primitive/Number.luau +21 -43
- package/src/codec/primitive/Varint.luau +67 -46
- package/src/index.d.ts +249 -335
- package/src/init.luau +319 -207
- package/src/internal/Baseline.luau +29 -24
- package/src/internal/Channel.luau +333 -278
- package/src/internal/Middleware.luau +60 -85
- package/src/internal/Pool.luau +19 -30
- package/src/internal/Registry.luau +56 -113
- package/src/transport/Bridge.luau +64 -43
- package/src/transport/Client.luau +59 -170
- package/src/transport/Gate.luau +282 -142
- package/src/transport/Reader.luau +148 -140
- package/src/transport/Server.luau +138 -488
- package/src/api/Namespace.luau +0 -256
- package/src/codec/meta/Quantized.luau +0 -174
|
@@ -1,233 +1,108 @@
|
|
|
1
1
|
--!strict
|
|
2
|
-
--!
|
|
2
|
+
--!optimize 2
|
|
3
3
|
-- Discriminated union codec. u8 variant tag + variant payload.
|
|
4
4
|
|
|
5
|
-
local
|
|
5
|
+
local Base = require(script.Parent.Parent.Base)
|
|
6
6
|
local Types = require(script.Parent.Parent.Parent.Types)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
type Codec<T> = Types.Codec<T>
|
|
10
|
-
type InternalCodec<T> = Types.InternalCodec<T>
|
|
8
|
+
-- Private -------------------------------------------------------------
|
|
11
9
|
|
|
12
|
-
local alloc =
|
|
10
|
+
local alloc = Base.alloc
|
|
11
|
+
local writeu8 = buffer.writeu8
|
|
12
|
+
local readu8 = buffer.readu8
|
|
13
13
|
|
|
14
14
|
-- Public --------------------------------------------------------------
|
|
15
15
|
|
|
16
16
|
local Tagged = {}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
function Tagged.define(
|
|
19
|
+
tagField: string,
|
|
20
|
+
variants: { [string]: Types.InternalCodec<any> }
|
|
21
|
+
): Types.InternalCodec<any>
|
|
22
|
+
if tagField == "" then
|
|
23
|
+
error("[Lync] Lync.tagged: tagField cannot be empty")
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
local names
|
|
26
|
+
local names: { string } = {}
|
|
25
27
|
for name in variants do
|
|
26
|
-
if #name == 0 then
|
|
27
|
-
error("[Lync] Tagged union variant name must not be empty")
|
|
28
|
-
end
|
|
29
28
|
table.insert(names, name)
|
|
30
29
|
end
|
|
31
30
|
table.sort(names)
|
|
32
31
|
|
|
33
|
-
local
|
|
34
|
-
if
|
|
35
|
-
error("[Lync]
|
|
36
|
-
end
|
|
37
|
-
if count > 256 then
|
|
38
|
-
error(`[Lync] Tagged union exceeds 256 variants: {count}`)
|
|
32
|
+
local variantCount = #names
|
|
33
|
+
if variantCount == 0 then
|
|
34
|
+
error("[Lync] Lync.tagged: requires at least one variant")
|
|
39
35
|
end
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
local tagCodecs = table.create(count) :: { Codec<any> }
|
|
43
|
-
local tagNames = table.create(count) :: { string }
|
|
44
|
-
local tagSizes = table.create(count) :: { number? }
|
|
45
|
-
|
|
46
|
-
local allDirect = true
|
|
47
|
-
local uniformSize: number? = (variants[names[1]] :: InternalCodec<any>)._size
|
|
48
|
-
local directWrites = table.create(count) :: { any }
|
|
49
|
-
local directReads = table.create(count) :: { any }
|
|
50
|
-
|
|
51
|
-
for i, name in names do
|
|
52
|
-
local codec = variants[name] :: InternalCodec<any>
|
|
53
|
-
nameToTag[name] = i
|
|
54
|
-
tagCodecs[i] = codec
|
|
55
|
-
tagNames[i] = name
|
|
56
|
-
|
|
57
|
-
local size = codec._size
|
|
58
|
-
tagSizes[i] = size
|
|
59
|
-
|
|
60
|
-
if size ~= uniformSize then
|
|
61
|
-
uniformSize = nil
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
local dw = codec._directWrite
|
|
65
|
-
local dr = codec._directRead
|
|
66
|
-
if dw and dr and size then
|
|
67
|
-
directWrites[i] = dw
|
|
68
|
-
directReads[i] = dr
|
|
69
|
-
else
|
|
70
|
-
allDirect = false
|
|
71
|
-
end
|
|
36
|
+
if variantCount > 256 then
|
|
37
|
+
error("[Lync] Lync.tagged: exceeds 256 variants")
|
|
72
38
|
end
|
|
73
39
|
|
|
40
|
+
-- Build lookup tables
|
|
41
|
+
local nameToTag: { [string]: number } = {}
|
|
42
|
+
local tagToCodec = table.create(variantCount)
|
|
43
|
+
local tagToName = table.create(variantCount)
|
|
74
44
|
local hasUnknown = false
|
|
75
|
-
|
|
76
|
-
|
|
45
|
+
|
|
46
|
+
for i = 1, variantCount do
|
|
47
|
+
local name = names[i]
|
|
48
|
+
local codec = variants[name]
|
|
49
|
+
nameToTag[name] = i - 1
|
|
50
|
+
tagToCodec[i] = codec
|
|
51
|
+
tagToName[i] = name
|
|
52
|
+
if (codec :: any)._hasUnknown then
|
|
77
53
|
hasUnknown = true
|
|
78
|
-
break
|
|
79
54
|
end
|
|
80
55
|
end
|
|
81
56
|
|
|
82
57
|
table.freeze(nameToTag)
|
|
83
|
-
table.freeze(
|
|
84
|
-
table.freeze(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
-- If uniform size, expose _directWrite/_directRead for parent struct/array
|
|
94
|
-
if fixedSize then
|
|
95
|
-
return table.freeze({
|
|
96
|
-
_size = fixedSize,
|
|
97
|
-
_hasUnknown = hasUnknown or nil,
|
|
98
|
-
_directWrite = function(b: buffer, offset: number, value: any): ()
|
|
99
|
-
local tag = nameToTag[value[tagField]]
|
|
100
|
-
if not tag then
|
|
101
|
-
error(`[Lync] Unknown variant: {value[tagField]}`)
|
|
102
|
-
end
|
|
103
|
-
buffer.writeu8(b, offset, tag - 1)
|
|
104
|
-
directWrites[tag](b, offset + 1, value)
|
|
105
|
-
end,
|
|
106
|
-
_directRead = function(b: buffer, offset: number): any
|
|
107
|
-
local tag = buffer.readu8(b, offset) + 1
|
|
108
|
-
local name = tagNames[tag]
|
|
109
|
-
if not name then
|
|
110
|
-
error(`[Lync] Unknown variant index: {tag - 1}`)
|
|
111
|
-
end
|
|
112
|
-
local data = directReads[tag](b, offset + 1)
|
|
113
|
-
if type(data) == "table" then
|
|
114
|
-
data[tagField] = name
|
|
115
|
-
end
|
|
116
|
-
return data
|
|
117
|
-
end,
|
|
118
|
-
write = function(ch: ChannelState, value: any): ()
|
|
119
|
-
local tag = nameToTag[value[tagField]]
|
|
120
|
-
if not tag then
|
|
121
|
-
error(`[Lync] Unknown variant: {value[tagField]}`)
|
|
122
|
-
end
|
|
123
|
-
local c = ch.cursor
|
|
124
|
-
if c + (fixedSize :: number) > ch.size then
|
|
125
|
-
alloc(ch, fixedSize :: number)
|
|
126
|
-
end
|
|
127
|
-
local b = ch.buff
|
|
128
|
-
buffer.writeu8(b, c, tag - 1)
|
|
129
|
-
directWrites[tag](b, c + 1, value)
|
|
130
|
-
ch.cursor = c + (fixedSize :: number)
|
|
131
|
-
end,
|
|
132
|
-
read = function(src: buffer, pos: number, _refs: { Instance }?): (any, number)
|
|
133
|
-
local tag = buffer.readu8(src, pos) + 1
|
|
134
|
-
local name = tagNames[tag]
|
|
135
|
-
if not name then
|
|
136
|
-
error(`[Lync] Unknown variant index: {tag - 1}`)
|
|
137
|
-
end
|
|
138
|
-
local data = directReads[tag](src, pos + 1)
|
|
139
|
-
if type(data) == "table" then
|
|
140
|
-
data[tagField] = name
|
|
141
|
-
end
|
|
142
|
-
return data, fixedSize :: number
|
|
143
|
-
end,
|
|
144
|
-
})
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
-- Non-uniform sizes but all have direct: use direct dispatch internally
|
|
148
|
-
local fieldSizes = table.clone(tagSizes) :: { number }
|
|
149
|
-
table.freeze(fieldSizes)
|
|
150
|
-
|
|
151
|
-
return table.freeze({
|
|
152
|
-
_size = nil,
|
|
153
|
-
_hasUnknown = hasUnknown or nil,
|
|
154
|
-
write = function(ch: ChannelState, value: any): ()
|
|
155
|
-
local tag = nameToTag[value[tagField]]
|
|
156
|
-
if not tag then
|
|
157
|
-
error(`[Lync] Unknown variant: {value[tagField]}`)
|
|
158
|
-
end
|
|
159
|
-
local varSize = fieldSizes[tag]
|
|
160
|
-
local totalNeeded = 1 + varSize
|
|
161
|
-
local c = ch.cursor
|
|
162
|
-
if c + totalNeeded > ch.size then
|
|
163
|
-
alloc(ch, totalNeeded)
|
|
164
|
-
end
|
|
165
|
-
local b = ch.buff
|
|
166
|
-
buffer.writeu8(b, c, tag - 1)
|
|
167
|
-
directWrites[tag](b, c + 1, value)
|
|
168
|
-
ch.cursor = c + totalNeeded
|
|
169
|
-
end,
|
|
170
|
-
read = function(src: buffer, pos: number, _refs: { Instance }?): (any, number)
|
|
171
|
-
local tag = buffer.readu8(src, pos) + 1
|
|
172
|
-
local name = tagNames[tag]
|
|
173
|
-
if not name then
|
|
174
|
-
error(`[Lync] Unknown variant index: {tag - 1}`)
|
|
175
|
-
end
|
|
176
|
-
local data = directReads[tag](src, pos + 1)
|
|
177
|
-
if type(data) == "table" then
|
|
178
|
-
data[tagField] = name
|
|
179
|
-
end
|
|
180
|
-
return data, 1 + fieldSizes[tag]
|
|
181
|
-
end,
|
|
182
|
-
})
|
|
183
|
-
end
|
|
58
|
+
table.freeze(tagToCodec)
|
|
59
|
+
table.freeze(tagToName)
|
|
60
|
+
|
|
61
|
+
local codec: any = {
|
|
62
|
+
write = function(ch: Types.ChannelState, value: any): ()
|
|
63
|
+
local name = value[tagField]
|
|
64
|
+
if name == nil then
|
|
65
|
+
error(`[Lync] Tagged: missing tagField "{tagField}" in value`)
|
|
66
|
+
end
|
|
184
67
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
writeFns[i] = tagCodecs[i].write
|
|
189
|
-
readFns[i] = tagCodecs[i].read
|
|
190
|
-
end
|
|
191
|
-
table.freeze(writeFns)
|
|
192
|
-
table.freeze(readFns)
|
|
193
|
-
|
|
194
|
-
return table.freeze({
|
|
195
|
-
_size = fixedSize,
|
|
196
|
-
_hasUnknown = hasUnknown or nil,
|
|
197
|
-
write = function(ch: ChannelState, value: any): ()
|
|
198
|
-
local tag = nameToTag[value[tagField]]
|
|
199
|
-
if not tag then
|
|
200
|
-
error(`[Lync] Unknown variant: {value[tagField]}`)
|
|
68
|
+
local tag = nameToTag[name]
|
|
69
|
+
if tag == nil then
|
|
70
|
+
error(`[Lync] Tagged: unknown variant "{name}"`)
|
|
201
71
|
end
|
|
202
72
|
|
|
203
|
-
local
|
|
204
|
-
if
|
|
205
|
-
alloc(ch, 1 + variantSize)
|
|
206
|
-
else
|
|
73
|
+
local cursor = ch.cursor
|
|
74
|
+
if cursor + 1 > ch.size then
|
|
207
75
|
alloc(ch, 1)
|
|
208
76
|
end
|
|
77
|
+
writeu8(ch.buff, cursor, tag)
|
|
78
|
+
ch.cursor = cursor + 1
|
|
209
79
|
|
|
210
|
-
|
|
211
|
-
buffer.writeu8(ch.buff, c, tag - 1)
|
|
212
|
-
ch.cursor = c + 1
|
|
213
|
-
writeFns[tag](ch, value)
|
|
80
|
+
tagToCodec[tag + 1].write(ch, value)
|
|
214
81
|
end,
|
|
82
|
+
|
|
215
83
|
read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
|
|
216
|
-
local tag =
|
|
217
|
-
local
|
|
218
|
-
if not
|
|
219
|
-
error(`[Lync]
|
|
84
|
+
local tag = readu8(src, pos)
|
|
85
|
+
local varCodec = tagToCodec[tag + 1]
|
|
86
|
+
if not varCodec then
|
|
87
|
+
error(`[Lync] Tagged: unknown tag {tag}`)
|
|
220
88
|
end
|
|
221
89
|
|
|
222
|
-
local
|
|
90
|
+
local name = tagToName[tag + 1]
|
|
91
|
+
local data, consumed = varCodec.read(src, pos + 1, refs)
|
|
223
92
|
|
|
93
|
+
-- Caller needs the tag field to discriminate the union
|
|
224
94
|
if type(data) == "table" then
|
|
225
95
|
data[tagField] = name
|
|
226
96
|
end
|
|
227
97
|
|
|
228
|
-
return data, 1 +
|
|
98
|
+
return data, 1 + consumed
|
|
229
99
|
end,
|
|
230
|
-
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if hasUnknown then
|
|
103
|
+
codec._hasUnknown = true
|
|
104
|
+
end
|
|
105
|
+
return table.freeze(codec)
|
|
231
106
|
end
|
|
232
107
|
|
|
233
108
|
return table.freeze(Tagged)
|
|
@@ -1,155 +1,131 @@
|
|
|
1
1
|
--!strict
|
|
2
|
-
--!
|
|
2
|
+
--!optimize 2
|
|
3
3
|
-- Positional ordered codec. Like struct but indexed, not keyed.
|
|
4
4
|
|
|
5
|
-
local
|
|
5
|
+
local Base = require(script.Parent.Parent.Base)
|
|
6
6
|
local Types = require(script.Parent.Parent.Parent.Types)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
type Codec<T> = Types.Codec<T>
|
|
10
|
-
type InternalCodec<T> = Types.InternalCodec<T>
|
|
8
|
+
-- Private -------------------------------------------------------------
|
|
11
9
|
|
|
12
|
-
local alloc =
|
|
10
|
+
local alloc = Base.alloc
|
|
13
11
|
|
|
14
12
|
-- Public --------------------------------------------------------------
|
|
15
13
|
|
|
16
14
|
local Tuple = {}
|
|
17
15
|
|
|
18
|
-
function Tuple.define(...:
|
|
16
|
+
function Tuple.define(...: Types.InternalCodec<any>): Types.InternalCodec<any>
|
|
19
17
|
local codecs = { ... }
|
|
20
18
|
local count = #codecs
|
|
21
19
|
if count == 0 then
|
|
22
|
-
error("[Lync]
|
|
20
|
+
error("[Lync] Lync.tuple: requires at least one codec")
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
-- Check if all codecs are direct
|
|
24
|
+
local allDirect = true
|
|
25
|
+
local totalSize = 0
|
|
27
26
|
local hasUnknown = false
|
|
27
|
+
|
|
28
28
|
for i = 1, count do
|
|
29
|
-
|
|
29
|
+
local c = codecs[i] :: any
|
|
30
|
+
if c._hasUnknown then
|
|
30
31
|
hasUnknown = true
|
|
31
|
-
break
|
|
32
32
|
end
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
local canDirect = true
|
|
36
|
-
local totalSize: number = 0
|
|
37
|
-
local directWrites = table.create(count) :: { any }
|
|
38
|
-
local directReads = table.create(count) :: { any }
|
|
39
|
-
local fieldSizes = table.create(count) :: { number }
|
|
40
|
-
|
|
41
|
-
for i = 1, count do
|
|
42
|
-
local internal = codecs[i] :: InternalCodec<any>
|
|
43
|
-
local size = internal._size
|
|
44
|
-
local dw = internal._directWrite
|
|
45
|
-
local dr = internal._directRead
|
|
46
|
-
|
|
47
|
-
if size and dw and dr then
|
|
48
|
-
fieldSizes[i] = size
|
|
49
|
-
directWrites[i] = dw
|
|
50
|
-
directReads[i] = dr
|
|
51
|
-
totalSize += size
|
|
33
|
+
if not c._size or not c._directWrite or not c._directRead then
|
|
34
|
+
allDirect = false
|
|
52
35
|
else
|
|
53
|
-
|
|
54
|
-
if size then
|
|
55
|
-
totalSize += size
|
|
56
|
-
else
|
|
57
|
-
totalSize = nil :: any
|
|
58
|
-
end
|
|
59
|
-
break
|
|
36
|
+
totalSize += c._size
|
|
60
37
|
end
|
|
61
38
|
end
|
|
62
39
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
40
|
+
table.freeze(codecs)
|
|
41
|
+
|
|
42
|
+
if allDirect then
|
|
43
|
+
-- Build precomputed offsets
|
|
44
|
+
local offsets = table.create(count)
|
|
45
|
+
local directWrites = table.create(count)
|
|
46
|
+
local directReads = table.create(count)
|
|
47
|
+
local cursor = 0
|
|
48
|
+
|
|
66
49
|
for i = 1, count do
|
|
67
|
-
local
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
break
|
|
73
|
-
end
|
|
50
|
+
local c = codecs[i] :: any
|
|
51
|
+
offsets[i] = cursor
|
|
52
|
+
directWrites[i] = c._directWrite
|
|
53
|
+
directReads[i] = c._directRead
|
|
54
|
+
cursor += c._size
|
|
74
55
|
end
|
|
75
|
-
end
|
|
76
56
|
|
|
77
|
-
|
|
57
|
+
table.freeze(offsets)
|
|
78
58
|
table.freeze(directWrites)
|
|
79
59
|
table.freeze(directReads)
|
|
80
|
-
table.freeze(fieldSizes)
|
|
81
60
|
|
|
82
|
-
local
|
|
83
|
-
|
|
84
|
-
directWrites[i](b, c, value[i])
|
|
85
|
-
c += fieldSizes[i]
|
|
86
|
-
end
|
|
87
|
-
end
|
|
61
|
+
local codec: any = {
|
|
62
|
+
_size = totalSize,
|
|
88
63
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
c += fieldSizes[i]
|
|
95
|
-
end
|
|
96
|
-
return result
|
|
97
|
-
end
|
|
64
|
+
_directWrite = function(b: buffer, off: number, value: any): ()
|
|
65
|
+
for i = 1, count do
|
|
66
|
+
directWrites[i](b, off + offsets[i], value[i])
|
|
67
|
+
end
|
|
68
|
+
end,
|
|
98
69
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
70
|
+
_directRead = function(b: buffer, off: number): any
|
|
71
|
+
local result = table.create(count)
|
|
72
|
+
for i = 1, count do
|
|
73
|
+
result[i] = directReads[i](b, off + offsets[i])
|
|
74
|
+
end
|
|
75
|
+
return result
|
|
76
|
+
end,
|
|
77
|
+
|
|
78
|
+
write = function(ch: Types.ChannelState, value: any): ()
|
|
105
79
|
local c = ch.cursor
|
|
106
80
|
if c + totalSize > ch.size then
|
|
107
81
|
alloc(ch, totalSize)
|
|
108
82
|
end
|
|
109
|
-
|
|
83
|
+
local b = ch.buff
|
|
84
|
+
for i = 1, count do
|
|
85
|
+
directWrites[i](b, c + offsets[i], value[i])
|
|
86
|
+
end
|
|
110
87
|
ch.cursor = c + totalSize
|
|
111
88
|
end,
|
|
112
|
-
|
|
113
|
-
|
|
89
|
+
|
|
90
|
+
read = function(src: buffer, pos: number, _refs: { Instance }?): (any, number)
|
|
91
|
+
local result = table.create(count)
|
|
92
|
+
for i = 1, count do
|
|
93
|
+
result[i] = directReads[i](src, pos + offsets[i])
|
|
94
|
+
end
|
|
95
|
+
return result, totalSize
|
|
114
96
|
end,
|
|
115
|
-
}
|
|
116
|
-
end
|
|
97
|
+
}
|
|
117
98
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
readFns[i] = codecs[i].read
|
|
99
|
+
if hasUnknown then
|
|
100
|
+
codec._hasUnknown = true
|
|
101
|
+
end
|
|
102
|
+
return table.freeze(codec)
|
|
123
103
|
end
|
|
124
|
-
table.freeze(writeFns)
|
|
125
|
-
table.freeze(readFns)
|
|
126
104
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
_size = totalSize,
|
|
131
|
-
_hasUnknown = hasUnknown or nil,
|
|
132
|
-
write = function(ch: ChannelState, value: { any }): ()
|
|
133
|
-
if hasFixedTotal then
|
|
134
|
-
alloc(ch, totalSize :: number)
|
|
135
|
-
end
|
|
105
|
+
-- Generic path
|
|
106
|
+
local codec: any = {
|
|
107
|
+
write = function(ch: Types.ChannelState, value: any): ()
|
|
136
108
|
for i = 1, count do
|
|
137
|
-
|
|
109
|
+
codecs[i].write(ch, value[i])
|
|
138
110
|
end
|
|
139
111
|
end,
|
|
140
|
-
read = function(src: buffer, pos: number, refs: { Instance }?): ({ any }, number)
|
|
141
|
-
local result = table.create(count)
|
|
142
|
-
local absPos = pos
|
|
143
112
|
|
|
113
|
+
read = function(src: buffer, pos: number, refs: { Instance }?): (any, number)
|
|
114
|
+
local result = table.create(count)
|
|
115
|
+
local total = 0
|
|
144
116
|
for i = 1, count do
|
|
145
|
-
local
|
|
146
|
-
result[i] =
|
|
147
|
-
|
|
117
|
+
local v, consumed = codecs[i].read(src, pos + total, refs)
|
|
118
|
+
result[i] = v
|
|
119
|
+
total += consumed
|
|
148
120
|
end
|
|
149
|
-
|
|
150
|
-
return result, absPos - pos
|
|
121
|
+
return result, total
|
|
151
122
|
end,
|
|
152
|
-
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if hasUnknown then
|
|
126
|
+
codec._hasUnknown = true
|
|
127
|
+
end
|
|
128
|
+
return table.freeze(codec)
|
|
153
129
|
end
|
|
154
130
|
|
|
155
131
|
return table.freeze(Tuple)
|
|
@@ -1,45 +1,73 @@
|
|
|
1
1
|
--!strict
|
|
2
|
-
--!
|
|
3
|
-
-- Raw buffer codec with varint length prefix.
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- Raw buffer codec with dense-prefix-varint length prefix.
|
|
4
4
|
|
|
5
|
-
local
|
|
5
|
+
local Base = require(script.Parent.Parent.Base)
|
|
6
6
|
local Types = require(script.Parent.Parent.Parent.Types)
|
|
7
7
|
local Varint = require(script.Parent.Parent.primitive.Varint)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
-- Private -------------------------------------------------------------
|
|
10
10
|
|
|
11
|
-
local alloc =
|
|
11
|
+
local alloc = Base.alloc
|
|
12
|
+
local INLINE = Varint.INLINE_MAX
|
|
12
13
|
|
|
13
14
|
-- Public --------------------------------------------------------------
|
|
14
15
|
|
|
15
|
-
local
|
|
16
|
+
local BufferCodec = {}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
BufferCodec.buff = table.freeze({
|
|
19
|
+
_typeCheck = "buffer",
|
|
20
|
+
|
|
21
|
+
write = function(ch: Types.ChannelState, value: buffer): ()
|
|
19
22
|
local len = buffer.len(value)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if
|
|
23
|
-
|
|
23
|
+
local cursor = ch.cursor
|
|
24
|
+
|
|
25
|
+
if len <= INLINE then
|
|
26
|
+
if cursor + 1 + len > ch.size then
|
|
27
|
+
alloc(ch, 1 + len)
|
|
28
|
+
end
|
|
29
|
+
local b = ch.buff
|
|
30
|
+
buffer.writeu8(b, cursor, len)
|
|
31
|
+
if len > 0 then
|
|
32
|
+
buffer.copy(b, cursor + 1, value, 0, len)
|
|
33
|
+
end
|
|
34
|
+
ch.cursor = cursor + 1 + len
|
|
35
|
+
else
|
|
36
|
+
Varint.write(ch, len)
|
|
37
|
+
cursor = ch.cursor
|
|
38
|
+
if cursor + len > ch.size then
|
|
39
|
+
alloc(ch, len)
|
|
40
|
+
end
|
|
41
|
+
buffer.copy(ch.buff, cursor, value, 0, len)
|
|
42
|
+
ch.cursor = cursor + len
|
|
24
43
|
end
|
|
25
|
-
buffer.copy(ch.buff, c, value, 0, len)
|
|
26
|
-
ch.cursor = c + len
|
|
27
44
|
end,
|
|
45
|
+
|
|
28
46
|
read = function(src: buffer, pos: number, _refs: { Instance }?): (buffer, number)
|
|
29
|
-
local
|
|
47
|
+
local b0 = buffer.readu8(src, pos)
|
|
48
|
+
local len: number
|
|
49
|
+
local lenBytes: number
|
|
50
|
+
|
|
51
|
+
if b0 <= INLINE then
|
|
52
|
+
len = b0
|
|
53
|
+
lenBytes = 1
|
|
54
|
+
else
|
|
55
|
+
len, lenBytes = Varint.read(src, pos)
|
|
56
|
+
end
|
|
57
|
+
|
|
30
58
|
if len == 0 then
|
|
31
59
|
return buffer.create(0), lenBytes
|
|
32
60
|
end
|
|
33
61
|
|
|
34
|
-
local
|
|
35
|
-
if len >
|
|
36
|
-
error(
|
|
62
|
+
local dataStart = pos + lenBytes
|
|
63
|
+
if dataStart + len > buffer.len(src) then
|
|
64
|
+
error("[Lync] Buffer: length exceeds remaining buffer")
|
|
37
65
|
end
|
|
38
66
|
|
|
39
67
|
local out = buffer.create(len)
|
|
40
|
-
buffer.copy(out, 0, src,
|
|
68
|
+
buffer.copy(out, 0, src, dataStart, len)
|
|
41
69
|
return out, lenBytes + len
|
|
42
70
|
end,
|
|
43
|
-
})
|
|
71
|
+
} :: any)
|
|
44
72
|
|
|
45
|
-
return table.freeze(
|
|
73
|
+
return table.freeze(BufferCodec)
|