@axpecter/lync 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +24 -24
  2. package/package.json +1 -1
  3. package/src/Types.luau +13 -2
  4. package/src/api/Group.luau +3 -5
  5. package/src/api/Namespace.luau +6 -6
  6. package/src/api/Packet.luau +9 -8
  7. package/src/api/Query.luau +11 -9
  8. package/src/api/Scope.luau +2 -2
  9. package/src/api/Signal.luau +10 -4
  10. package/src/codec/Base.luau +7 -3
  11. package/src/codec/composite/Array.luau +18 -15
  12. package/src/codec/composite/Map.luau +45 -31
  13. package/src/codec/composite/Optional.luau +3 -2
  14. package/src/codec/composite/Shared.luau +7 -5
  15. package/src/codec/composite/Struct.luau +6 -4
  16. package/src/codec/composite/Tagged.luau +6 -6
  17. package/src/codec/composite/Tuple.luau +9 -7
  18. package/src/codec/datatype/Buffer.luau +3 -2
  19. package/src/codec/datatype/CFrame.luau +2 -1
  20. package/src/codec/datatype/Instance.luau +3 -2
  21. package/src/codec/datatype/Sequence.luau +3 -4
  22. package/src/codec/datatype/String.luau +3 -6
  23. package/src/codec/meta/Auto.luau +77 -72
  24. package/src/codec/meta/Bitfield.luau +5 -4
  25. package/src/codec/meta/Enum.luau +6 -5
  26. package/src/codec/meta/Quantized.luau +5 -4
  27. package/src/codec/meta/Unknown.luau +5 -1
  28. package/src/codec/primitive/Float16.luau +5 -4
  29. package/src/codec/primitive/Varint.luau +2 -2
  30. package/src/init.luau +39 -37
  31. package/src/internal/Baseline.luau +6 -2
  32. package/src/internal/Channel.luau +11 -6
  33. package/src/internal/Middleware.luau +13 -12
  34. package/src/internal/Pool.luau +5 -5
  35. package/src/internal/Registry.luau +4 -4
  36. package/src/transport/Bridge.luau +4 -3
  37. package/src/transport/Client.luau +4 -3
  38. package/src/transport/Gate.luau +5 -5
  39. package/src/transport/Reader.luau +3 -3
  40. package/src/transport/Server.luau +7 -8
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  ```toml
15
15
  [dependencies]
16
- Lync = "axp3cter/lync@1.4.0"
16
+ Lync = "axp3cter/lync@1.4.1"
17
17
  ```
18
18
 
19
19
  **npm (roblox-ts)**
@@ -33,7 +33,7 @@ Or grab the `.rbxm` from [releases](https://github.com/Axp3cter/Lync/releases/la
33
33
 
34
34
  ## Example
35
35
 
36
- **Shared** (ReplicatedStorage, required by both)
36
+ **Shared**
37
37
 
38
38
  ```luau
39
39
  local Lync = require(game.ReplicatedStorage.Lync)
@@ -163,7 +163,7 @@ end
163
163
  | | What it does |
164
164
  |:---------|:------------|
165
165
  | `Lync.start()` | Sets up transport. Server creates remotes, client connects. Call once after all definitions. |
166
- | `Lync.VERSION` | `"1.4.0"` |
166
+ | `Lync.VERSION` | `"1.4.1"` |
167
167
 
168
168
  ## Packets
169
169
 
@@ -198,9 +198,9 @@ packet:send(data) -- send to server
198
198
 
199
199
  | Method | What it does |
200
200
  |:-------|:------------|
201
- | `packet:listen(fn(data, sender))` | Listen for incoming. Returns a Connection. Sender is `Player` on server, `nil` on client. |
202
- | `packet:once(fn(data, sender))` | Same as listen but auto-disconnects after one fire. |
203
- | `packet:wait()` | Yields until next fire. Returns `(data, sender)`. |
201
+ | `packet:listen(fn(data, sender))` | Sender is `Player` on server, `nil` on client. Returns a Connection. |
202
+ | `packet:once(fn(data, sender))` | Auto-disconnects after one fire. |
203
+ | `packet:wait()` | Returns `(data, sender)`. |
204
204
  | `packet:disconnectAll()` | Kills all listeners on this packet. |
205
205
 
206
206
  ## Queries
@@ -248,7 +248,7 @@ Returned by `packet:listen()`, `packet:once()`, `query:listen()`, and `ns:listen
248
248
 
249
249
  | | What it does |
250
250
  |:-------|:------------|
251
- | `connection.connected` | `true` if still connected, `false` after disconnect. |
251
+ | `connection.connected` | `boolean` |
252
252
  | `connection:disconnect()` | Stops the listener. |
253
253
 
254
254
  ## Scope
@@ -267,11 +267,11 @@ scope:destroy() -- disconnects everything
267
267
 
268
268
  | Method | What it does |
269
269
  |:-------|:------------|
270
- | `scope:listen(source, fn)` | Calls source:listen(fn) and tracks the connection. |
271
- | `scope:once(source, fn)` | Calls source:once(fn) and tracks the connection. |
272
- | `scope:listenAll(namespace, fn)` | Calls namespace:listenAll(fn) and tracks the connection. |
273
- | `scope:add(connection)` | Track a raw Connection or RBXScriptConnection. |
274
- | `scope:destroy()` | Disconnects all tracked connections. Safe to call multiple times. |
270
+ | `scope:listen(source, fn)` | Calls `source:listen(fn)` and tracks the connection. |
271
+ | `scope:once(source, fn)` | Calls `source:once(fn)` and tracks the connection. |
272
+ | `scope:listenAll(namespace, fn)` | Calls `namespace:listenAll(fn)` and tracks the connection. |
273
+ | `scope:add(connection)` | Also accepts RBXScriptConnection. |
274
+ | `scope:destroy()` | Safe to call multiple times. |
275
275
 
276
276
  ## Groups
277
277
 
@@ -291,11 +291,11 @@ packet:send(data, vips)
291
291
  |:-------|:--------|:-------------|
292
292
  | `group:add(player)` | `boolean` | `true` if added, `false` if already in. |
293
293
  | `group:remove(player)` | `boolean` | `true` if removed, `false` if wasnt in there. |
294
- | `group:has(player)` | `boolean` | |
295
- | `group:count()` | `number` | |
296
- | `group:getSet()` | `{ [Player]: true }` | |
297
- | `group:forEach(fn)` | | Calls `fn(player)` for each member. |
298
- | `group:destroy()` | | Removes the group and all memberships. |
294
+ | `group:has(player)` | `boolean` | Whether the player is in the group. |
295
+ | `group:count()` | `number` | Number of members. |
296
+ | `group:getSet()` | `{ [Player]: true }` | Snapshot of the internal set. |
297
+ | `group:forEach(fn)` | `()` | Calls `fn(player)` for each member. |
298
+ | `group:destroy()` | `()` | Removes the group and all memberships. |
299
299
 
300
300
  ## Middleware
301
301
 
@@ -415,10 +415,10 @@ Reliable only. Lync will error if you try to use these with `unreliable = true`.
415
415
 
416
416
  | Scenario | Without Lync | With Lync | FPS |
417
417
  |:---------|------------:|---------:|----:|
418
- | Static booleans (1B) | 480 Kbps | **2.45 Kbps** | 59.98 |
419
- | Static entities (34B) | 16,320 Kbps | **2.52 Kbps** | 60.00 |
420
- | Moving entities | 16,320 Kbps | **3.51 Kbps** | 59.99 |
421
- | Chaotic entities | 16,320 Kbps | **4.66 Kbps** | 59.99 |
418
+ | Static booleans (1B) | 480 Kbps | **2.34 Kbps** | 60.00 |
419
+ | Static entities (34B) | 16,320 Kbps | **2.62 Kbps** | 60.00 |
420
+ | Moving entities | 16,320 Kbps | **3.14 Kbps** | 60.00 |
421
+ | Chaotic entities | 16,320 Kbps | **4.76 Kbps** | 59.99 |
422
422
 
423
423
  ### Cross-Library Comparison
424
424
 
@@ -437,7 +437,7 @@ Same data shapes and methodology as [Blink's benchmark suite](https://github.com
437
437
  | Tool (Kbps) | Median | P0 | P80 | P90 | P95 | P100 |
438
438
  |:------------|-------:|---:|----:|----:|----:|-----:|
439
439
  | roblox | 559,364 | 559,364 | 676,715 | 676,715 | 676,715 | 784,081 |
440
- | **lync** | **3.59** | 3.50 | 3.61 | 3.62 | 3.62 | 4.86 |
440
+ | **lync** | **3.61** | 3.53 | 3.63 | 3.64 | 3.64 | 4.64 |
441
441
  | blink | 41.81 | 26.30 | 42.40 | 42.48 | 42.48 | 42.62 |
442
442
  | zap | 41.71 | 25.46 | 42.19 | 42.32 | 42.32 | 42.93 |
443
443
  | bytenet | 41.64 | 22.84 | 42.36 | 42.82 | 42.82 | 43.24 |
@@ -447,7 +447,7 @@ Same data shapes and methodology as [Blink's benchmark suite](https://github.com
447
447
  | Tool (FPS) | Median | P0 | P80 | P90 | P95 | P100 |
448
448
  |:-----------|-------:|---:|----:|----:|----:|-----:|
449
449
  | roblox | 21.00 | 22.00 | 20.00 | 19.00 | 19.00 | 19.00 |
450
- | **lync** | **60.00** | 61.00 | 60.00 | 59.00 | 59.00 | 58.00 |
450
+ | **lync** | **60.00** | 61.00 | 60.00 | 60.00 | 60.00 | 59.00 |
451
451
  | blink | 97.00 | 98.00 | 97.00 | 96.00 | 96.00 | 96.00 |
452
452
  | zap | 52.00 | 53.00 | 51.00 | 51.00 | 51.00 | 49.00 |
453
453
  | bytenet | 35.00 | 37.00 | 35.00 | 35.00 | 35.00 | 34.00 |
@@ -455,7 +455,7 @@ Same data shapes and methodology as [Blink's benchmark suite](https://github.com
455
455
  | Tool (Kbps) | Median | P0 | P80 | P90 | P95 | P100 |
456
456
  |:------------|-------:|---:|----:|----:|----:|-----:|
457
457
  | roblox | 353,107 | 196,826 | 690,747 | 842,240 | 842,240 | 1,124,176 |
458
- | **lync** | **4.31** | 3.77 | 4.33 | 4.34 | 4.34 | 4.43 |
458
+ | **lync** | **4.31** | 3.85 | 4.36 | 4.38 | 4.38 | 4.44 |
459
459
  | blink | 7.91 | 7.41 | 7.93 | 7.99 | 7.99 | 8.00 |
460
460
  | zap | 8.10 | 5.75 | 8.17 | 8.22 | 8.22 | 8.27 |
461
461
  | bytenet | 8.11 | 5.07 | 8.35 | 8.46 | 8.46 | 8.47 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axpecter/lync",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Buffer networking for Roblox. Delta compression, XOR framing, built-in security.",
5
5
  "main": "src/init.luau",
6
6
  "types": "src/index.d.ts",
package/src/Types.luau CHANGED
@@ -1,6 +1,6 @@
1
1
  --!strict
2
2
  --!optimize 2
3
- -- Shared type definitions.
3
+ -- Shared type definitions for the Lync networking library.
4
4
 
5
5
  export type ChannelState = {
6
6
  buff: buffer,
@@ -10,7 +10,7 @@ export type ChannelState = {
10
10
  lastId: number,
11
11
  countPos: number,
12
12
  itemCount: number,
13
- deltas: { [number]: any },
13
+ deltas: { [number]: any }, -- per-codec delta caches; shape varies by codec kind
14
14
  prevDump: buffer?,
15
15
  }
16
16
 
@@ -19,6 +19,17 @@ export type Codec<T> = {
19
19
  read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
20
20
  }
21
21
 
22
+ -- Extended codec exposing internal fast-path metadata used by composite codecs.
23
+ export type InternalCodec<T> = {
24
+ write: (ch: ChannelState, value: T) -> (),
25
+ read: (src: buffer, pos: number, refs: { Instance }?) -> (T, number),
26
+ _size: number?,
27
+ _directWrite: ((b: buffer, offset: number, value: T) -> ())?,
28
+ _directRead: ((b: buffer, offset: number) -> T)?,
29
+ _isDelta: boolean?,
30
+ _isBool: boolean?,
31
+ }
32
+
22
33
  export type RateLimitConfig = {
23
34
  maxPerSecond: number,
24
35
  burstAllowance: number?,
@@ -4,13 +4,13 @@
4
4
 
5
5
  local Players = game:GetService ("Players")
6
6
 
7
- -- State ------------------------------------------------------------------
7
+ -- State --------------------------------------------------------------
8
8
 
9
9
  local _groups = {} :: { [string]: { [Player]: true } }
10
10
  local _counts = {} :: { [string]: number }
11
11
  local _playerGroups = {} :: { [Player]: { [string]: true } }
12
12
 
13
- -- Private ----------------------------------------------------------------
13
+ -- Private ------------------------------------------------------------
14
14
 
15
15
  local function onPlayerRemoving (player: Player): ()
16
16
  local memberships = _playerGroups[player]
@@ -31,8 +31,6 @@ end
31
31
 
32
32
  Players.PlayerRemoving:Connect (onPlayerRemoving)
33
33
 
34
- -- GroupImpl ---------------------------------------------------------------
35
-
36
34
  local GroupImpl = {}
37
35
  GroupImpl.__index = GroupImpl
38
36
 
@@ -139,7 +137,7 @@ end
139
137
 
140
138
  table.freeze (GroupImpl)
141
139
 
142
- -- Public -----------------------------------------------------------------
140
+ -- Public -------------------------------------------------------------
143
141
 
144
142
  local Group = {}
145
143
 
@@ -11,16 +11,16 @@ type Connection = Types.Connection
11
11
  type PacketConfig<T> = Types.PacketConfig<T>
12
12
  type QueryConfig<R, S> = Types.QueryConfig<R, S>
13
13
 
14
- -- Constants --------------------------------------------------------------
14
+ -- Constants ----------------------------------------------------------
15
15
 
16
16
  local MAX_NAMESPACES = 64
17
17
 
18
- -- State ------------------------------------------------------------------
18
+ -- State --------------------------------------------------------------
19
19
 
20
20
  local _registered = {} :: { [string]: true }
21
21
  local _count = 0
22
22
 
23
- -- Private ----------------------------------------------------------------
23
+ -- Private ------------------------------------------------------------
24
24
 
25
25
  type NamespaceConfig = {
26
26
  packets: { [string]: PacketConfig<any> }?,
@@ -47,8 +47,6 @@ local function scopedHandler (
47
47
  end
48
48
  end
49
49
 
50
- -- Namespace --------------------------------------------------------------
51
-
52
50
  local NamespaceImpl = {}
53
51
  NamespaceImpl.__index = NamespaceImpl
54
52
 
@@ -173,7 +171,9 @@ function NamespaceImpl.queryNames (self: any): { string }
173
171
  return result
174
172
  end
175
173
 
176
- -- Public -----------------------------------------------------------------
174
+ table.freeze (NamespaceImpl)
175
+
176
+ -- Public -------------------------------------------------------------
177
177
 
178
178
  local Namespace = {}
179
179
 
@@ -11,9 +11,10 @@ local Signal = require (script.Parent.Signal)
11
11
  local Types = require (script.Parent.Parent.Types)
12
12
 
13
13
  type Connection = Types.Connection
14
+ type InternalCodec<T> = Types.InternalCodec<T>
14
15
  type PacketConfig<T> = Types.PacketConfig<T>
15
16
 
16
- -- Constants --------------------------------------------------------------
17
+ -- Constants ----------------------------------------------------------
17
18
 
18
19
  local IS_SERVER = RunService:IsServer ()
19
20
 
@@ -24,7 +25,10 @@ local serverWriteToAllExcept = Server.writeToAllExcept
24
25
  local serverWriteToSet = Server.writeToSet
25
26
  local clientWrite = Client.write
26
27
 
27
- -- Private ----------------------------------------------------------------
28
+ local DELTA_TARGETED = 1
29
+ local DELTA_BROADCAST = 2
30
+
31
+ -- Private ------------------------------------------------------------
28
32
 
29
33
  -- Shared methods (both contexts)
30
34
  local SharedImpl = {}
@@ -49,9 +53,6 @@ end
49
53
  local ServerImpl = setmetatable ({}, { __index = SharedImpl })
50
54
  ServerImpl.__index = ServerImpl
51
55
 
52
- local DELTA_TARGETED = 1
53
- local DELTA_BROADCAST = 2
54
-
55
56
  local function checkDeltaMode (self: any, mode: number): ()
56
57
  if not self._isDelta then
57
58
  return
@@ -122,7 +123,7 @@ end
122
123
 
123
124
  table.freeze (ClientImpl)
124
125
 
125
- -- Public -----------------------------------------------------------------
126
+ -- Public -------------------------------------------------------------
126
127
 
127
128
  local Packet = {}
128
129
 
@@ -136,7 +137,7 @@ function Packet.define (name: string, config: PacketConfig<any>): any
136
137
 
137
138
  local isUnreliable = config.unreliable or false
138
139
 
139
- if (config.value :: any)._isDelta and isUnreliable then
140
+ if (config.value :: InternalCodec<any>)._isDelta and isUnreliable then
140
141
  error (`[Lync] Delta codec requires reliable delivery: "{name}"`)
141
142
  end
142
143
 
@@ -152,7 +153,7 @@ function Packet.define (name: string, config: PacketConfig<any>): any
152
153
  config.maxPayloadBytes
153
154
  )
154
155
 
155
- local isDelta = (config.value :: any)._isDelta == true
156
+ local isDelta = (config.value :: InternalCodec<any>)._isDelta == true
156
157
 
157
158
  return setmetatable ({
158
159
  _id = reg.id,
@@ -14,14 +14,14 @@ local Types = require (script.Parent.Parent.Types)
14
14
  type Connection = Types.Connection
15
15
  type QueryConfig<R, S> = Types.QueryConfig<R, S>
16
16
 
17
- -- Constants --------------------------------------------------------------
17
+ -- Constants ----------------------------------------------------------
18
18
 
19
19
  local IS_SERVER = RunService:IsServer ()
20
20
 
21
21
  -- Wire ceiling: correlationId is u16 in Channel.writeQuery / Reader.process.
22
22
  local POOL_SIZE = 65536
23
23
 
24
- -- State ------------------------------------------------------------------
24
+ -- State --------------------------------------------------------------
25
25
 
26
26
  type PendingQuery = {
27
27
  thread: thread?,
@@ -33,7 +33,7 @@ local _pending = {} :: { [number]: PendingQuery }
33
33
  local _nextId = 0
34
34
  local _activeCount = 0
35
35
 
36
- -- Private ----------------------------------------------------------------
36
+ -- Private ------------------------------------------------------------
37
37
 
38
38
  local function allocCorrelation (): number
39
39
  if _activeCount >= POOL_SIZE then
@@ -53,7 +53,9 @@ local function allocCorrelation (): number
53
53
  return id
54
54
  end
55
55
 
56
- local function freeCorrelation (): ()
56
+ -- Decrements the active correlation counter. Does not free a specific slot;
57
+ -- that is handled by nil-ing _pending[id] at the call site.
58
+ local function releaseCorrelation (): ()
57
59
  _activeCount -= 1
58
60
  end
59
61
 
@@ -64,7 +66,7 @@ local function completeQuery (id: number, data: any): ()
64
66
  end
65
67
 
66
68
  _pending[id] = nil
67
- freeCorrelation ()
69
+ releaseCorrelation ()
68
70
 
69
71
  if entry.timeout then
70
72
  task.cancel (entry.timeout)
@@ -158,7 +160,7 @@ local function requestMulti (self: any, players: { Player }, data: any): { [Play
158
160
  local entry = _pending[cid]
159
161
  if entry then
160
162
  _pending[cid] = nil
161
- freeCorrelation ()
163
+ releaseCorrelation ()
162
164
  end
163
165
  end
164
166
 
@@ -176,8 +178,6 @@ local function requestMulti (self: any, players: { Player }, data: any): { [Play
176
178
  return coroutine.yield ()
177
179
  end
178
180
 
179
- -- Query ------------------------------------------------------------------
180
-
181
181
  local QueryImpl = {}
182
182
  QueryImpl.__index = QueryImpl
183
183
 
@@ -274,7 +274,9 @@ function QueryImpl.requestGroup (self: any, group: any, data: any): { [Player]:
274
274
  return requestMulti (self, players, data)
275
275
  end
276
276
 
277
- -- Public -----------------------------------------------------------------
277
+ table.freeze (QueryImpl)
278
+
279
+ -- Public -------------------------------------------------------------
278
280
 
279
281
  local Query = {}
280
282
 
@@ -2,7 +2,7 @@
2
2
  --!optimize 2
3
3
  -- Batched connection lifecycle management.
4
4
 
5
- -- Private ----------------------------------------------------------------
5
+ -- Private ------------------------------------------------------------
6
6
 
7
7
  local ScopeImpl = {}
8
8
  ScopeImpl.__index = ScopeImpl
@@ -62,7 +62,7 @@ end
62
62
 
63
63
  table.freeze (ScopeImpl)
64
64
 
65
- -- Public -----------------------------------------------------------------
65
+ -- Public -------------------------------------------------------------
66
66
 
67
67
  local Scope = {}
68
68
 
@@ -6,12 +6,13 @@ local Types = require (script.Parent.Parent.Types)
6
6
 
7
7
  type Connection = Types.Connection
8
8
 
9
- -- Listener state: single numeric field for both connected and once checks.
9
+ -- Constants ----------------------------------------------------------
10
+
10
11
  local STATE_DISCONNECTED = 0
11
12
  local STATE_CONNECTED = 1
12
13
  local STATE_ONCE = 2
13
14
 
14
- -- Private ----------------------------------------------------------------
15
+ -- Private ------------------------------------------------------------
15
16
 
16
17
  local _freeThread: thread? = nil
17
18
 
@@ -36,7 +37,9 @@ local function spawn (fn: (...any) -> (), ...: any): ()
36
37
  task.spawn (_freeThread :: thread, fn, ...)
37
38
  end
38
39
 
39
- -- Entry doubles as the Connection handle , 1 alloc per listener instead of 2.
40
+ -- Entry doubles as the Connection handle: 1 alloc per listener instead of 2.
41
+ -- self: any — metatable typing via typeof(setmetatable) is not practical here
42
+ -- because Entry and Signal reference each other circularly.
40
43
  local EntryImpl = {}
41
44
  EntryImpl.__index = EntryImpl
42
45
 
@@ -213,7 +216,10 @@ function SignalImpl.disconnectAll (self: any): ()
213
216
  self._count = 0
214
217
  end
215
218
 
216
- -- Public -----------------------------------------------------------------
219
+ table.freeze (EntryImpl)
220
+ table.freeze (SignalImpl)
221
+
222
+ -- Public -------------------------------------------------------------
217
223
 
218
224
  local Signal = {}
219
225
 
@@ -3,9 +3,13 @@
3
3
  -- Fixed-size codec factory. Every fixed-size codec calls Base.define once.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.internal.Channel)
6
+ local Types = require (script.Parent.Parent.Types)
7
+
8
+ type ChannelState = Types.ChannelState
9
+
6
10
  local alloc = Channel.alloc
7
11
 
8
- -- Public -----------------------------------------------------------------
12
+ -- Public -------------------------------------------------------------
9
13
 
10
14
  local Base = {}
11
15
 
@@ -18,7 +22,7 @@ function Base.define <T>(
18
22
  _size = size,
19
23
  _directWrite = directWrite,
20
24
  _directRead = directRead,
21
- write = function (ch: any, value: T): ()
25
+ write = function (ch: ChannelState, value: T): ()
22
26
  local c = ch.cursor
23
27
  if c + size > ch.size then
24
28
  alloc (ch, size)
@@ -39,7 +43,7 @@ function Base.zero (): any
39
43
  _directRead = function (_b: buffer, _offset: number): any
40
44
  return nil
41
45
  end,
42
- write = function (_ch: any, _value: any): () end,
46
+ write = function (_ch: ChannelState, _value: any): () end,
43
47
  read = function (_src: buffer, _pos: number, _refs: { Instance }?): (any, number)
44
48
  return nil, 0
45
49
  end,
@@ -4,14 +4,15 @@
4
4
 
5
5
  local Baseline = require (script.Parent.Parent.Parent.internal.Baseline)
6
6
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
7
- local alloc = Channel.alloc
8
7
  local Shared = require (script.Parent.Shared)
9
8
  local Types = require (script.Parent.Parent.Parent.Types)
9
+ local Varint = require (script.Parent.Parent.primitive.Varint)
10
10
 
11
11
  type ChannelState = Types.ChannelState
12
12
  type Codec<T> = Types.Codec<T>
13
- local Varint = require (script.Parent.Parent.primitive.Varint)
13
+ type InternalCodec<T> = Types.InternalCodec<T>
14
14
 
15
+ local alloc = Channel.alloc
15
16
  local rangeEqual = Shared.rangeEqual
16
17
  local acquireScratch = Shared.acquireScratch
17
18
  local releaseScratch = Shared.releaseScratch
@@ -20,7 +21,7 @@ local FLAG_DELTA = Shared.FLAG_DELTA
20
21
  local FLAG_FULL = Shared.FLAG_FULL
21
22
  local FLAG_UNCHANGED = Shared.FLAG_UNCHANGED
22
23
 
23
- -- Public -----------------------------------------------------------------
24
+ -- Public -------------------------------------------------------------
24
25
 
25
26
  local Array = {}
26
27
 
@@ -30,9 +31,10 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
30
31
  local writeElement = element.write
31
32
  local readElement = element.read
32
33
 
33
- local elemSize = (element :: any)._size :: number?
34
- local elemDirect = (element :: any)._directWrite
35
- local elemDRead = (element :: any)._directRead
34
+ local internal = element :: InternalCodec<any>
35
+ local elemSize = internal._size
36
+ local elemWrite = internal._directWrite
37
+ local elemRead = internal._directRead
36
38
 
37
39
  return table.freeze ({
38
40
  _isDelta = true,
@@ -45,13 +47,13 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
45
47
  local bounds = table.create (len + 1)
46
48
  bounds[1] = 0
47
49
 
48
- if elemDirect and elemSize then
50
+ if elemWrite and elemSize then
49
51
  local totalBytes = len * elemSize
50
52
  alloc (scratch, totalBytes)
51
53
  local b = scratch.buff
52
54
  local c = 0
53
55
  for i = 1, len do
54
- elemDirect (b, c, value[i])
56
+ elemWrite (b, c, value[i])
55
57
  c += elemSize
56
58
  bounds[i + 1] = c
57
59
  end
@@ -147,9 +149,9 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
147
149
 
148
150
  local result = table.create (len)
149
151
 
150
- if elemDRead and elemSize then
152
+ if elemRead and elemSize then
151
153
  for i = 1, len do
152
- result[i] = elemDRead (src, absPos)
154
+ result[i] = elemRead (src, absPos)
153
155
  absPos += elemSize
154
156
  end
155
157
  else
@@ -174,8 +176,8 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
174
176
  local idx, idxBytes = Varint.read (src, absPos)
175
177
  absPos += idxBytes
176
178
 
177
- if elemDRead and elemSize then
178
- result[idx + 1] = elemDRead (src, absPos)
179
+ if elemRead and elemSize then
180
+ result[idx + 1] = elemRead (src, absPos)
179
181
  absPos += elemSize
180
182
  else
181
183
  local val, n = readElement (src, absPos, refs)
@@ -191,9 +193,10 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
191
193
  end
192
194
 
193
195
  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
196
+ local internal = element :: InternalCodec<any>
197
+ local elementSize = internal._size
198
+ local directWrite = internal._directWrite
199
+ local directRead = internal._directRead
197
200
 
198
201
  if elementSize and directWrite and directRead then
199
202
  return table.freeze ({