@axpecter/lync 2.3.2 → 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.
- package/LICENSE +21 -0
- package/README.md +302 -299
- package/Types.luau +215 -0
- package/api/Define.luau +154 -0
- package/api/Lifecycle.luau +119 -0
- package/api/Packet.luau +108 -0
- package/api/Query.luau +149 -0
- package/api/Set.luau +189 -0
- package/channel/Blocks.luau +124 -0
- package/channel/Group.luau +118 -0
- package/channel/Link.luau +135 -0
- package/channel/Outbox.luau +261 -0
- package/channel/Recipients.luau +129 -0
- package/channel/Transport.luau +138 -0
- package/codec/Base.luau +236 -0
- package/codec/Composites.luau +128 -0
- package/codec/Datatypes.luau +162 -0
- package/codec/Legality.luau +61 -0
- package/codec/Scalars.luau +72 -0
- package/codec/Text.luau +89 -0
- package/codec/init.luau +39 -0
- package/index.d.ts +285 -0
- package/init.luau +91 -0
- package/kernel/Bits.luau +16 -0
- package/kernel/Catalog.luau +121 -0
- package/kernel/Heap.luau +80 -0
- package/kernel/Listeners.luau +95 -0
- package/kernel/Log.luau +197 -0
- package/kernel/Tally.luau +128 -0
- package/kernel/Threads.luau +44 -0
- package/kernel/Wide.luau +267 -0
- package/package.json +15 -32
- package/runtime/Boundary.luau +180 -0
- package/runtime/Dispatch.luau +91 -0
- package/runtime/Handles.luau +114 -0
- package/runtime/Handshake.luau +90 -0
- package/runtime/Pending.luau +196 -0
- package/runtime/Router.luau +379 -0
- package/runtime/Session.luau +731 -0
- package/shape/Compile.luau +340 -0
- package/shape/Folds.luau +332 -0
- package/shape/Frames.luau +170 -0
- package/shape/Grid.luau +169 -0
- package/shape/Ir.luau +540 -0
- package/shape/Joins.luau +125 -0
- package/shape/Legality.luau +273 -0
- package/shape/Lower.luau +419 -0
- package/shape/Order.luau +64 -0
- package/shape/Regions.luau +113 -0
- package/shape/Rotation.luau +472 -0
- package/shape/Serial.luau +258 -0
- package/shape/Words.luau +89 -0
- package/shape/emit/Block.luau +453 -0
- package/shape/emit/Column.luau +338 -0
- package/shape/emit/Leaf.luau +462 -0
- package/shape/emit/Word.luau +234 -0
- package/shape/emit/init.luau +222 -0
- package/shape/init.luau +78 -0
- package/state/Apply.luau +330 -0
- package/state/Audience.luau +126 -0
- package/state/Catchup.luau +218 -0
- package/state/Coalesce.luau +43 -0
- package/state/Fieldset.luau +177 -0
- package/state/Newest.luau +339 -0
- package/state/Plan.luau +441 -0
- package/state/Sections.luau +468 -0
- package/state/Store.luau +188 -0
- package/state/Sync.luau +762 -0
- package/wire/Bytes.luau +118 -0
- package/wire/Clock.luau +37 -0
- package/wire/Protocol.luau +110 -0
- package/wire/Sequence.luau +40 -0
- package/wire/Varint.luau +124 -0
- package/src/Types.luau +0 -180
- package/src/api/Group.luau +0 -156
- package/src/api/Packet.luau +0 -319
- package/src/api/Query.luau +0 -338
- package/src/api/Scope.luau +0 -90
- package/src/api/Signal.luau +0 -188
- package/src/codec/Base.luau +0 -136
- package/src/codec/composite/Array.luau +0 -456
- package/src/codec/composite/Map.luau +0 -469
- package/src/codec/composite/Optional.luau +0 -54
- package/src/codec/composite/Shared.luau +0 -291
- package/src/codec/composite/Struct.luau +0 -494
- package/src/codec/composite/Tagged.luau +0 -103
- package/src/codec/composite/Tuple.luau +0 -143
- package/src/codec/datatype/Buffer.luau +0 -66
- package/src/codec/datatype/CFrame.luau +0 -109
- package/src/codec/datatype/Color.luau +0 -32
- package/src/codec/datatype/Instance.luau +0 -52
- package/src/codec/datatype/IntVector.luau +0 -39
- package/src/codec/datatype/NumberRange.luau +0 -39
- package/src/codec/datatype/Ray.luau +0 -36
- package/src/codec/datatype/Rect.luau +0 -31
- package/src/codec/datatype/Region.luau +0 -62
- package/src/codec/datatype/Sequence.luau +0 -184
- package/src/codec/datatype/String.luau +0 -94
- package/src/codec/datatype/UDim.luau +0 -46
- package/src/codec/datatype/Vector.luau +0 -130
- package/src/codec/meta/Auto.luau +0 -318
- package/src/codec/meta/Bitfield.luau +0 -147
- package/src/codec/meta/Custom.luau +0 -33
- package/src/codec/meta/DeltaScalar.luau +0 -390
- package/src/codec/meta/Enum.luau +0 -50
- package/src/codec/meta/Float.luau +0 -38
- package/src/codec/meta/Nothing.luau +0 -13
- package/src/codec/meta/Unknown.luau +0 -41
- package/src/codec/primitive/Bool.luau +0 -26
- package/src/codec/primitive/Float16.luau +0 -99
- package/src/codec/primitive/Int.luau +0 -59
- package/src/codec/primitive/Number.luau +0 -24
- package/src/codec/primitive/Signed.luau +0 -32
- package/src/codec/primitive/Varint.luau +0 -165
- package/src/codec/primitive/Zint.luau +0 -99
- package/src/index.d.ts +0 -423
- package/src/init.luau +0 -362
- package/src/internal/Baseline.luau +0 -57
- package/src/internal/Channel.luau +0 -390
- package/src/internal/Middleware.luau +0 -100
- package/src/internal/Pool.luau +0 -65
- package/src/internal/Registry.luau +0 -119
- package/src/internal/Transport.luau +0 -28
- package/src/transport/Bridge.luau +0 -110
- package/src/transport/Client.luau +0 -97
- package/src/transport/Gate.luau +0 -488
- package/src/transport/Reader.luau +0 -331
- package/src/transport/Server.luau +0 -211
- package/src/util/Array.luau +0 -18
- package/src/util/Buffer.luau +0 -90
- package/src/util/Constants.luau +0 -30
- package/src/util/Log.luau +0 -68
- package/src/util/Player.luau +0 -14
- package/src/util/Quantize.luau +0 -84
- package/src/util/Quat.luau +0 -124
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!native
|
|
3
|
+
--!optimize 2
|
|
4
|
+
-- A shape and everything under it, as the one pair of closures the whole tree became.
|
|
5
|
+
|
|
6
|
+
local Base = require (script.Parent.Parent.codec.Base)
|
|
7
|
+
local Block = require (script.Block)
|
|
8
|
+
local Catalog = require (script.Parent.Parent.kernel.Catalog)
|
|
9
|
+
local Ir = require (script.Parent.Ir)
|
|
10
|
+
local Leaf = require (script.Leaf)
|
|
11
|
+
local Log = require (script.Parent.Parent.kernel.Log)
|
|
12
|
+
local Serial = require (script.Parent.Serial)
|
|
13
|
+
local Types = require (script.Parent.Parent.Types)
|
|
14
|
+
local Word = require (script.Word)
|
|
15
|
+
|
|
16
|
+
local Emit = {}
|
|
17
|
+
|
|
18
|
+
-- Constants -----------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
-- Types ---------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
-- Everything a walk needs that is not the node it is on.
|
|
23
|
+
export type Site = {
|
|
24
|
+
read paths: Serial.Interner,
|
|
25
|
+
read expected: Serial.Interner,
|
|
26
|
+
read sidecar: Ir.Sidecar,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
-- State ---------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
-- The first reason a check gave while one payload was decoding, held until that payload is done.
|
|
32
|
+
local parkedPath: number? = nil
|
|
33
|
+
local parkedReason: string? = nil
|
|
34
|
+
|
|
35
|
+
-- Private -------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
-- Every check a place declared, in the order they were declared, and the first reason one gives.
|
|
38
|
+
local function turned (tag: Ir.Tag, value: any, ctx: Types.ValidateContext)
|
|
39
|
+
local checks = tag.checks :: { Base.Validate }
|
|
40
|
+
|
|
41
|
+
for index = 1, #checks do
|
|
42
|
+
local why = checks[index] (value, ctx)
|
|
43
|
+
if why == nil then continue end
|
|
44
|
+
|
|
45
|
+
if parkedPath == nil then
|
|
46
|
+
parkedPath = tag.pathId
|
|
47
|
+
parkedReason = why
|
|
48
|
+
end
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
-- A node's own checks, wrapped round the read once here so a node without any pays for nothing.
|
|
54
|
+
local function checked (read: Ir.Read, tag: Ir.Tag): Ir.Read
|
|
55
|
+
return function (b: buffer, pos: number, ctx: Types.ValidateContext): (number, any)
|
|
56
|
+
local at, value = read (b, pos, ctx)
|
|
57
|
+
turned (tag, value, ctx)
|
|
58
|
+
return at, value
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
-- Where a region's field sits in the record the group answers, as the names to walk to reach it.
|
|
63
|
+
local function chained (of: Ir.Group, join: Ir.Join): { string }
|
|
64
|
+
local key = join.key
|
|
65
|
+
local out: { string } = if key == nil then {} else { key }
|
|
66
|
+
|
|
67
|
+
local at = join.nest
|
|
68
|
+
while at ~= nil do
|
|
69
|
+
local nest = of.nests[at]
|
|
70
|
+
table.insert (out, 1, nest.key)
|
|
71
|
+
at = nest.under
|
|
72
|
+
end
|
|
73
|
+
return out
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
-- The checks of a region's fields, wrapped round the group that holds the region.
|
|
77
|
+
local function fielded (read: Ir.Read, of: Ir.Group): Ir.Read
|
|
78
|
+
local word = of.word
|
|
79
|
+
if word == nil then return read end
|
|
80
|
+
|
|
81
|
+
local looks: { Ir.Join } = {}
|
|
82
|
+
local within: { { string } } = {}
|
|
83
|
+
|
|
84
|
+
for _, join in word.joins do
|
|
85
|
+
if join.tag.checks == nil then continue end
|
|
86
|
+
|
|
87
|
+
table.insert (looks, join)
|
|
88
|
+
table.insert (within, chained (of, join))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
local reach = #looks
|
|
92
|
+
if reach == 0 then return read end
|
|
93
|
+
|
|
94
|
+
return function (b: buffer, pos: number, ctx: Types.ValidateContext): (number, any)
|
|
95
|
+
local at, value = read (b, pos, ctx)
|
|
96
|
+
|
|
97
|
+
for index = 1, reach do
|
|
98
|
+
local one = value
|
|
99
|
+
for _, name in within[index] do
|
|
100
|
+
one = one[name]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
turned (looks[index].tag, one, ctx)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return at, value
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
-- One node to its pair, with its children already theirs.
|
|
111
|
+
local function made (of: Ir.Shape, at: Site): (Ir.Write, Ir.Read)
|
|
112
|
+
local paths, expected = at.paths, at.expected
|
|
113
|
+
|
|
114
|
+
--[[
|
|
115
|
+
A region alone is a record with no fields after it. It has joins and so it has a value, but
|
|
116
|
+
the pair that lays a region down fills an array rather than answering, and the thing that
|
|
117
|
+
turns that into a value is the group. So a bare one is emitted as the group it means.
|
|
118
|
+
]]
|
|
119
|
+
if of.op == "word" then return made (Ir.group (of.tag, of, {}), at) end
|
|
120
|
+
|
|
121
|
+
if of.op == "wide" then return Leaf.wide (of, paths, expected) end
|
|
122
|
+
if of.op == "f32" or of.op == "f64" then return Leaf.float (of, paths, expected) end
|
|
123
|
+
if of.op == "vlq" or of.op == "vli" then return Leaf.varint (of, paths, expected) end
|
|
124
|
+
if of.op == "bytes" then return Leaf.bytes (of, paths, expected) end
|
|
125
|
+
if of.op == "run" then return Leaf.run (of, paths, expected) end
|
|
126
|
+
|
|
127
|
+
if of.op == "group" then
|
|
128
|
+
local word = of.word
|
|
129
|
+
local pack: Word.Pack?, unpack: Word.Unpack?
|
|
130
|
+
if word ~= nil then
|
|
131
|
+
pack, unpack = Word.emit (word, paths, expected)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
local reach = #of.parts
|
|
135
|
+
local writes = table.create (reach) :: { Ir.Write }
|
|
136
|
+
local reads = table.create (reach) :: { Ir.Read }
|
|
137
|
+
|
|
138
|
+
for index, part in of.parts do
|
|
139
|
+
writes[index], reads[index] = Emit.emit (part.of, at)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
local write, read = Block.group (of, pack, unpack, writes, reads, paths, expected)
|
|
143
|
+
return write, fielded (read, of)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
if of.op == "apart" then
|
|
147
|
+
local reach = #of.parts
|
|
148
|
+
local writes = table.create (reach) :: { Ir.Write }
|
|
149
|
+
local reads = table.create (reach) :: { Ir.Read }
|
|
150
|
+
|
|
151
|
+
for index, part in of.parts do
|
|
152
|
+
writes[index], reads[index] = Emit.emit (part, at)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
return Block.apart (of, writes, reads, paths, expected)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
if of.op == "list" then
|
|
159
|
+
local write, read = Emit.emit (of.elem, at)
|
|
160
|
+
return Block.list (of, write, read, paths, expected)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if of.op == "pairs" then
|
|
164
|
+
local writeKey, readKey = Emit.emit (of.key, at)
|
|
165
|
+
local writeValue, readValue = Emit.emit (of.value, at)
|
|
166
|
+
|
|
167
|
+
return Block.pairs (of, writeKey, readKey, writeValue, readValue, paths, expected)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
--[[
|
|
171
|
+
An optional is its own value and a bit of the region beside it, and the bit is the group's.
|
|
172
|
+
So there is no closure here that a present field does not already have, and an absent one is
|
|
173
|
+
a call the group does not make.
|
|
174
|
+
]]
|
|
175
|
+
if of.op == "opt" then return Emit.emit (of.inner, at) end
|
|
176
|
+
|
|
177
|
+
if of.op == "branch" then
|
|
178
|
+
local reach = #of.arms
|
|
179
|
+
local writes = table.create (reach) :: { Ir.Write }
|
|
180
|
+
local reads = table.create (reach) :: { Ir.Read }
|
|
181
|
+
|
|
182
|
+
for index, arm in of.arms do
|
|
183
|
+
writes[index], reads[index] = Emit.emit (arm, at)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
return Block.branch (of, writes, reads, paths, expected)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
if of.op == "xform" then
|
|
190
|
+
local write, read = Emit.emit (of.inner, at)
|
|
191
|
+
return Block.xform (of, write, read)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
return Leaf.slot (of, paths, expected, at.sidecar)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
-- Public --------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
-- A shape and everything under it, as the pair the whole tree became.
|
|
200
|
+
function Emit.emit (of: Ir.Shape, at: Site): (Ir.Write, Ir.Read)
|
|
201
|
+
local write, read = made (of, at)
|
|
202
|
+
local held = if of.tag.checks == nil then read else checked (read, of.tag)
|
|
203
|
+
|
|
204
|
+
-- The root, which is the one place a parked reason becomes a refusal.
|
|
205
|
+
local function taken (b: buffer, pos: number, ctx: Types.ValidateContext): (number, any)
|
|
206
|
+
parkedPath = nil
|
|
207
|
+
parkedReason = nil
|
|
208
|
+
|
|
209
|
+
local ends, value = held (b, pos, ctx)
|
|
210
|
+
if parkedPath == nil then return ends, value end
|
|
211
|
+
|
|
212
|
+
local path, reason = parkedPath, parkedReason
|
|
213
|
+
parkedPath = nil
|
|
214
|
+
parkedReason = nil
|
|
215
|
+
|
|
216
|
+
return Log.reject (Catalog.VALIDATE, { pathId = path, reason = reason, at = ends })
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
return write, taken
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
return table.freeze (Emit)
|
package/shape/init.luau
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- One declaration to the pair that writes it and reads it back, which is the whole compile path.
|
|
4
|
+
|
|
5
|
+
local Base = require (script.Parent.codec.Base)
|
|
6
|
+
local Emit = require (script.emit)
|
|
7
|
+
local Grid = require (script.Grid)
|
|
8
|
+
local Ir = require (script.Ir)
|
|
9
|
+
local Lower = require (script.Lower)
|
|
10
|
+
local Serial = require (script.Serial)
|
|
11
|
+
local Types = require (script.Parent.Types)
|
|
12
|
+
|
|
13
|
+
local Shape = {}
|
|
14
|
+
|
|
15
|
+
-- Types ---------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
-- What a build interns and what it hands a sidecar, declared below and passed on unchanged.
|
|
18
|
+
export type Site = Emit.Site
|
|
19
|
+
|
|
20
|
+
-- A declaration compiled: the pair, what it costs, and the facts everything above reads off it.
|
|
21
|
+
export type Built = {
|
|
22
|
+
read cell: Base.Cell,
|
|
23
|
+
read write: Ir.Write,
|
|
24
|
+
read read: Ir.Read,
|
|
25
|
+
read maxBytes: number,
|
|
26
|
+
read fixed: boolean,
|
|
27
|
+
read tag: Ir.Tag,
|
|
28
|
+
read grid: Grid.Grid?,
|
|
29
|
+
read marker: Base.Marker,
|
|
30
|
+
read sidecar: Ir.Sidecar,
|
|
31
|
+
read paths: Serial.Interner,
|
|
32
|
+
read expected: Serial.Interner,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
-- Private -------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
-- The grid a whole declaration is one index on, where it is one, and nothing where it is not.
|
|
38
|
+
local function gridded (of: Ir.Shape): Grid.Grid?
|
|
39
|
+
if of.op == "xform" then return gridded (of.inner) end
|
|
40
|
+
if of.op == "wide" then return of.grid end
|
|
41
|
+
if of.op ~= "word" then return nil end
|
|
42
|
+
|
|
43
|
+
-- A pull spreads one value over several leaves, so there is no single index to answer with.
|
|
44
|
+
if of.joins[1].pull ~= nil then return nil end
|
|
45
|
+
return of.leaves[1]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
-- Public --------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
-- A codec and where a refusal inside it says it is, as the build everything above holds.
|
|
51
|
+
function Shape.build (of: Types.Codec<any>, at: string, shared: Site?): Built
|
|
52
|
+
local cell = Base.cell (of)
|
|
53
|
+
local site: Site = shared
|
|
54
|
+
or {
|
|
55
|
+
paths = Serial.interner (),
|
|
56
|
+
expected = Serial.interner (),
|
|
57
|
+
sidecar = { refs = {}, slotOf = {}, bears = false },
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
local shape = Lower.of (cell, at, site)
|
|
61
|
+
local write, read = Emit.emit (shape, site)
|
|
62
|
+
|
|
63
|
+
return table.freeze ({
|
|
64
|
+
cell = cell,
|
|
65
|
+
write = write,
|
|
66
|
+
read = read,
|
|
67
|
+
maxBytes = shape.maxBytes,
|
|
68
|
+
fixed = shape.fixed,
|
|
69
|
+
tag = shape.tag,
|
|
70
|
+
grid = gridded (shape),
|
|
71
|
+
marker = cell.marker,
|
|
72
|
+
sidecar = site.sidecar,
|
|
73
|
+
paths = site.paths,
|
|
74
|
+
expected = site.expected,
|
|
75
|
+
})
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return table.freeze (Shape)
|
package/state/Apply.luau
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!optimize 2
|
|
3
|
+
-- The one path a section becomes a store by, which both machines run over the same sections.
|
|
4
|
+
|
|
5
|
+
local Protocol = require (script.Parent.Parent.wire.Protocol)
|
|
6
|
+
local Sections = require (script.Parent.Sections)
|
|
7
|
+
local Store = require (script.Parent.Store)
|
|
8
|
+
local Types = require (script.Parent.Parent.Types)
|
|
9
|
+
|
|
10
|
+
local Apply = {}
|
|
11
|
+
|
|
12
|
+
-- Constants -----------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const KEYFRAME = Protocol.SECTION_KEYFRAME
|
|
15
|
+
const DELTA = Protocol.SECTION_DELTA
|
|
16
|
+
const REMOVAL = Protocol.SECTION_REMOVAL
|
|
17
|
+
|
|
18
|
+
-- The two causes a section can be read as, which is every cause there is.
|
|
19
|
+
const REMOVED: Types.Cause = "removed"
|
|
20
|
+
const CLEARED: Types.Cause = "cleared"
|
|
21
|
+
|
|
22
|
+
-- What a frame came to for one record, which is everything a caller can be told about one.
|
|
23
|
+
const NOTHING = 0
|
|
24
|
+
const ARRIVED = NOTHING + 1
|
|
25
|
+
const CHANGED = ARRIVED + 1
|
|
26
|
+
const GONE = CHANGED + 1
|
|
27
|
+
const REPLACED = GONE + 1
|
|
28
|
+
|
|
29
|
+
-- Types ---------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
--[[
|
|
32
|
+
What a frame did to one set, held per set rather than per partition because an id is unique
|
|
33
|
+
across the set and a slot is not. `net` is what the frame came to for each record and the whole
|
|
34
|
+
of what a caller is told, `added`, `changed` and `gone` are that taken apart for the fan, `olds`
|
|
35
|
+
is the record as it stood, and `shadow` is the slots a keyframe spoke for.
|
|
36
|
+
]]
|
|
37
|
+
export type Heard = {
|
|
38
|
+
watching: boolean,
|
|
39
|
+
net: { [number]: number },
|
|
40
|
+
left: { [number]: Store.Store },
|
|
41
|
+
added: { number },
|
|
42
|
+
changed: { number },
|
|
43
|
+
gone: { number },
|
|
44
|
+
causes: { [number]: Types.Cause },
|
|
45
|
+
olds: { [number]: Store.Record },
|
|
46
|
+
shadow: { [Store.Store]: { [number]: boolean } },
|
|
47
|
+
owed: number,
|
|
48
|
+
holds: { { [number]: number } },
|
|
49
|
+
where: { number },
|
|
50
|
+
marks: { number },
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
-- Private -------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
-- What a partition's keyframes have spoken for this frame, made where the first one is applied.
|
|
56
|
+
local function shadowed (of: Heard, store: Store.Store): { [number]: boolean }
|
|
57
|
+
local held = of.shadow[store]
|
|
58
|
+
if held ~= nil then return held end
|
|
59
|
+
|
|
60
|
+
local made: { [number]: boolean } = {}
|
|
61
|
+
of.shadow[store] = made
|
|
62
|
+
return made
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
-- A baseline a keyframe stated, kept until every section of the frame has been read.
|
|
66
|
+
local function owes (of: Heard, held: { [number]: number }, slot: number, mark: number)
|
|
67
|
+
local at = of.owed + 1
|
|
68
|
+
|
|
69
|
+
of.owed = at
|
|
70
|
+
of.holds[at] = held
|
|
71
|
+
of.where[at] = slot
|
|
72
|
+
of.marks[at] = mark
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
-- Whether the record as it stood before this frame is worth keeping at all.
|
|
76
|
+
local function kept (of: Heard, id: number): boolean return of.watching and of.olds[id] == nil end
|
|
77
|
+
|
|
78
|
+
-- The record as it stood, kept where it lies, because this one is on its way out.
|
|
79
|
+
local function shed (of: Heard, store: Store.Store, id: number)
|
|
80
|
+
if not kept (of, id) then return end
|
|
81
|
+
|
|
82
|
+
local row = store.rows[id]
|
|
83
|
+
if row == nil then return end
|
|
84
|
+
|
|
85
|
+
of.olds[id] = row
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
-- The record as it stood before this frame, taken once and only where something wants it.
|
|
89
|
+
local function snapped (of: Heard, store: Store.Store, id: number)
|
|
90
|
+
if not kept (of, id) then return end
|
|
91
|
+
|
|
92
|
+
local row = store.rows[id]
|
|
93
|
+
if row == nil then return end
|
|
94
|
+
|
|
95
|
+
of.olds[id] = table.clone (row)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
-- The same, for the lane that does not come through a section.
|
|
99
|
+
function Apply.snapped (of: Heard, store: Store.Store, id: number) snapped (of, store, id) end
|
|
100
|
+
|
|
101
|
+
-- A record established, which is an arrival unless this frame has already taken it away.
|
|
102
|
+
local function born (of: Heard, store: Store.Store, id: number)
|
|
103
|
+
local was = of.net[id]
|
|
104
|
+
|
|
105
|
+
if was == GONE then
|
|
106
|
+
of.net[id] = if of.left[id] == store then REPLACED else CHANGED
|
|
107
|
+
return
|
|
108
|
+
end
|
|
109
|
+
if was == CHANGED or was == REPLACED then return end
|
|
110
|
+
|
|
111
|
+
of.net[id] = ARRIVED
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
local function moved (of: Heard, id: number) Apply.moved (of, id) end
|
|
115
|
+
|
|
116
|
+
-- A record taken away, which cancels an arrival rather than following it.
|
|
117
|
+
local function lost (of: Heard, store: Store.Store, id: number, why: Types.Cause)
|
|
118
|
+
if of.net[id] == ARRIVED then
|
|
119
|
+
of.net[id] = NOTHING
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
of.net[id] = GONE
|
|
124
|
+
of.left[id] = store
|
|
125
|
+
of.causes[id] = why
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
--[[
|
|
129
|
+
A partition emptied, and every record it held reported gone.
|
|
130
|
+
|
|
131
|
+
Read before the store is emptied rather than after, which is the only order there is: what a
|
|
132
|
+
clear says is every record this receiver held, and afterwards it holds none.
|
|
133
|
+
]]
|
|
134
|
+
local function emptied (store: Store.Store, of: Heard)
|
|
135
|
+
for id in store.rows do
|
|
136
|
+
shed (of, store, id)
|
|
137
|
+
lost (of, store, id, CLEARED)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
Store.clear (store)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
--[[
|
|
144
|
+
The listed records gone. A slot this receiver does not hold is a specified no-op rather than a
|
|
145
|
+
fault, since a removal is broadcast and an audience is what decides who was holding one.
|
|
146
|
+
]]
|
|
147
|
+
local function dropped (store: Store.Store, frame: Sections.Frame, of: Heard)
|
|
148
|
+
for index = 1, frame.count do
|
|
149
|
+
local id = store.ids[frame.slots[index] ]
|
|
150
|
+
if id == nil then continue end
|
|
151
|
+
|
|
152
|
+
shed (of, store, id)
|
|
153
|
+
Store.unbind (store, id)
|
|
154
|
+
lost (of, store, id, REMOVED)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
--[[
|
|
159
|
+
The listed records established: bound to the slots the other machine chose, at the generations
|
|
160
|
+
it stated, with every field of every one of them written whole.
|
|
161
|
+
]]
|
|
162
|
+
local function established (store: Store.Store, layout: Sections.Layout, of: Heard)
|
|
163
|
+
local frame = layout.frame
|
|
164
|
+
local shadow = shadowed (of, store)
|
|
165
|
+
local gens = store.gens
|
|
166
|
+
|
|
167
|
+
for index = 1, frame.count do
|
|
168
|
+
local slot = frame.slots[index]
|
|
169
|
+
local id = frame.ids[index]
|
|
170
|
+
local was = store.slotOf[id]
|
|
171
|
+
|
|
172
|
+
snapped (of, store, id)
|
|
173
|
+
Store.hold (store, id, slot)
|
|
174
|
+
if gens ~= nil then gens[slot] = frame.gens[index] end
|
|
175
|
+
|
|
176
|
+
shadow[slot] = true
|
|
177
|
+
if was == nil then
|
|
178
|
+
born (of, store, id)
|
|
179
|
+
else
|
|
180
|
+
moved (of, id)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
for field = 1, layout.def.fieldCount do
|
|
185
|
+
local values = frame.values[field]
|
|
186
|
+
local marks = frame.at[field]
|
|
187
|
+
local held = store.prev[field]
|
|
188
|
+
|
|
189
|
+
for index = 1, frame.count do
|
|
190
|
+
local slot = frame.slots[index]
|
|
191
|
+
|
|
192
|
+
Store.write (store, slot, field, values[index])
|
|
193
|
+
if held ~= nil then owes (of, held, slot, marks[index]) end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
--[[
|
|
199
|
+
The listed differences applied, for the slots this receiver holds and this frame has not already
|
|
200
|
+
spoken for.
|
|
201
|
+
]]
|
|
202
|
+
local function advanced (store: Store.Store, layout: Sections.Layout, of: Heard)
|
|
203
|
+
local frame = layout.frame
|
|
204
|
+
local chosen = frame.chosen
|
|
205
|
+
local shadow = shadowed (of, store)
|
|
206
|
+
local ids = store.ids
|
|
207
|
+
|
|
208
|
+
for place = 1, chosen.count do
|
|
209
|
+
local field = chosen.fields[place]
|
|
210
|
+
local under = frame.under[place]
|
|
211
|
+
local values = frame.values[field]
|
|
212
|
+
local marks = frame.at[field]
|
|
213
|
+
local held = store.prev[field]
|
|
214
|
+
|
|
215
|
+
for index = 1, frame.covered[place] do
|
|
216
|
+
local slot = under[index]
|
|
217
|
+
local id = ids[slot]
|
|
218
|
+
if id == nil or shadow[slot] then continue end
|
|
219
|
+
|
|
220
|
+
local before = store.columns[field][slot]
|
|
221
|
+
|
|
222
|
+
snapped (of, store, id)
|
|
223
|
+
Store.write (store, slot, field, values[index])
|
|
224
|
+
if held ~= nil then held[slot] = marks[index] end
|
|
225
|
+
|
|
226
|
+
-- A value that arrived as what the field already held is no change to report.
|
|
227
|
+
if before ~= values[index] then moved (of, id) end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
-- Public --------------------------------------------------------------
|
|
233
|
+
|
|
234
|
+
-- One record changed, said once however many times a frame says it.
|
|
235
|
+
function Apply.moved (of: Heard, id: number)
|
|
236
|
+
local was = of.net[id]
|
|
237
|
+
if was == ARRIVED or was == REPLACED then return end
|
|
238
|
+
|
|
239
|
+
of.net[id] = CHANGED
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
-- What the frame came to, as the three lists the fan reads, each in id order.
|
|
243
|
+
function Apply.parted (of: Heard): ({ number }, { number }, { number })
|
|
244
|
+
local gone, added, changed = of.gone, of.added, of.changed
|
|
245
|
+
|
|
246
|
+
table.clear (gone)
|
|
247
|
+
table.clear (added)
|
|
248
|
+
table.clear (changed)
|
|
249
|
+
|
|
250
|
+
for id, net in of.net do
|
|
251
|
+
if net == GONE or net == REPLACED then table.insert (gone, id) end
|
|
252
|
+
if net == ARRIVED or net == REPLACED then table.insert (added, id) end
|
|
253
|
+
if net == CHANGED then table.insert (changed, id) end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
table.sort (gone)
|
|
257
|
+
table.sort (added)
|
|
258
|
+
table.sort (changed)
|
|
259
|
+
|
|
260
|
+
return gone, added, changed
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
-- What a frame did to one set, empty, which a set holds one of for as long as it exists.
|
|
264
|
+
function Apply.heard (): Heard
|
|
265
|
+
return {
|
|
266
|
+
watching = false,
|
|
267
|
+
net = {},
|
|
268
|
+
left = {},
|
|
269
|
+
added = {},
|
|
270
|
+
changed = {},
|
|
271
|
+
gone = {},
|
|
272
|
+
causes = {},
|
|
273
|
+
olds = {},
|
|
274
|
+
shadow = {},
|
|
275
|
+
owed = 0,
|
|
276
|
+
holds = {},
|
|
277
|
+
where = {},
|
|
278
|
+
marks = {},
|
|
279
|
+
}
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
-- One section, into the partition it is about.
|
|
283
|
+
function Apply.section (store: Store.Store, layout: Sections.Layout, kind: number, of: Heard)
|
|
284
|
+
if kind == KEYFRAME then
|
|
285
|
+
established (store, layout, of)
|
|
286
|
+
return
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
if kind == DELTA then
|
|
290
|
+
advanced (store, layout, of)
|
|
291
|
+
return
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
if kind == REMOVAL then
|
|
295
|
+
dropped (store, layout.frame, of)
|
|
296
|
+
return
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
emptied (store, of)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
-- The frame over: what its keyframes owe, paid, and what they spoke for, forgotten.
|
|
303
|
+
function Apply.settle (of: Heard)
|
|
304
|
+
for index = 1, of.owed do
|
|
305
|
+
of.holds[index][of.where[index] ] = of.marks[index]
|
|
306
|
+
end
|
|
307
|
+
of.owed = 0
|
|
308
|
+
|
|
309
|
+
for _, held in of.shadow do
|
|
310
|
+
table.clear (held)
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
--[[
|
|
315
|
+
What the frame did, forgotten, which is what a caller does once it has said so.
|
|
316
|
+
|
|
317
|
+
Apart from the settling because the two answer to different things: the baselines are owed to
|
|
318
|
+
the next frame and cannot wait on anybody, and this waits on every listener having run.
|
|
319
|
+
]]
|
|
320
|
+
function Apply.forget (of: Heard)
|
|
321
|
+
table.clear (of.net)
|
|
322
|
+
table.clear (of.left)
|
|
323
|
+
table.clear (of.added)
|
|
324
|
+
table.clear (of.changed)
|
|
325
|
+
table.clear (of.gone)
|
|
326
|
+
table.clear (of.causes)
|
|
327
|
+
table.clear (of.olds)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
return table.freeze (Apply)
|