@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
@@ -0,0 +1,340 @@
1
+ --!strict
2
+ --!optimize 2
3
+ -- A namespace of declarations as the frozen records every layer above reads it by.
4
+
5
+ local Base = require (script.Parent.Parent.codec.Base)
6
+ local Frames = require (script.Parent.Frames)
7
+ local Legality = require (script.Parent.Legality)
8
+ local Log = require (script.Parent.Parent.kernel.Log)
9
+ local Order = require (script.Parent.Order)
10
+ local Serial = require (script.Parent.Serial)
11
+ local Shape = require (script.Parent)
12
+ local Types = require (script.Parent.Parent.Types)
13
+ local Wide = require (script.Parent.Parent.kernel.Wide)
14
+
15
+ local Compile = {}
16
+
17
+ -- Constants -----------------------------------------------------------
18
+
19
+ -- What a template holds in every field, which is a place rather than a value.
20
+ const PLACE = false
21
+
22
+ -- Types ---------------------------------------------------------------
23
+
24
+ -- What one definition costs, as the two numbers a caller of it can want.
25
+ export type Packet = {
26
+ read id: number,
27
+ read name: string,
28
+ read kind: "packet",
29
+ read maxBytes: number,
30
+ read file: string,
31
+ read line: number,
32
+ read built: Shape.Built,
33
+ read head: Frames.Head,
34
+ read blockBytes: number,
35
+ read delivery: Serial.Delivery,
36
+ read hz: number?,
37
+ read timestamped: boolean,
38
+ }
39
+
40
+ --[[
41
+ A query holds two builds and one id, and its response is that id and one. A frame carries a
42
+ single axis and no kind bit, so which half arrived is read off whether the id is the one the
43
+ record carries, a comparison the router already holds both sides of.
44
+ ]]
45
+ export type Query = {
46
+ read id: number,
47
+ read name: string,
48
+ read kind: "query",
49
+ read maxBytes: number,
50
+ read file: string,
51
+ read line: number,
52
+ read request: Shape.Built,
53
+ read response: Shape.Built,
54
+ read asks: Frames.Head,
55
+ read answers: Frames.Head,
56
+ read blockBytes: number,
57
+ }
58
+
59
+ --[[
60
+ A set is its fields, so what it carries is per field and in one order. The record's own cell is
61
+ here and its own build is not, since a section never writes a whole record and the cell is all
62
+ the descriptor ever wanted. Which fields may hold nothing and which may only climb are beside
63
+ the builds, because reading either off a cell at the call would be `state` reading a codec.
64
+ ]]
65
+ export type Set = {
66
+ read id: number,
67
+ read name: string,
68
+ read kind: "set",
69
+ read maxBytes: number,
70
+ read file: string,
71
+ read line: number,
72
+ read cell: Base.Cell,
73
+ read head: Frames.Head,
74
+ read stream: Frames.Head,
75
+ read keyField: string?,
76
+ read keyIndex: number?,
77
+ read fieldNames: { string },
78
+ read fieldIndex: { [string]: number },
79
+ read fieldBuilt: { Shape.Built },
80
+ read fieldCount: number,
81
+ read newestFields: { number },
82
+ read optionalFields: { boolean },
83
+ read climbingFields: { boolean },
84
+ read template: { [string]: any },
85
+ read site: Shape.Site,
86
+ }
87
+
88
+ -- The marker vocabulary, re-exported rather than reached for.
89
+ export type Marker = Base.Marker
90
+
91
+ export type Def = Packet | Query | Set
92
+
93
+ --[[
94
+ A namespace, compiled. `count` is how many ids were handed out rather than how many definitions
95
+ there are, because a defId is a ranged int over exactly that and a query took two.
96
+ ]]
97
+ export type Compiled = {
98
+ read space: string,
99
+ read descriptor: string,
100
+ read hash: Wide.Word,
101
+ read count: number,
102
+ read list: { Def },
103
+ read byName: { [string]: Def },
104
+ read byId: { [number]: Def },
105
+ }
106
+
107
+ -- A set's fields, as the four arrays a column walk reads and the bytes one record comes to.
108
+ type Fields = {
109
+ names: { string },
110
+ index: { [string]: number },
111
+ built: { Shape.Built },
112
+ newest: { number },
113
+ optional: { boolean },
114
+ climbs: { boolean },
115
+ template: { [string]: any },
116
+ site: Shape.Site,
117
+ bytes: number,
118
+ }
119
+
120
+ -- Private -------------------------------------------------------------
121
+
122
+ -- A handle as the declaration it carries.
123
+ local function declared (of: Types.Definition): Legality.Declared return of :: any end
124
+
125
+ -- A set's fields, in the order their columns are indexed by.
126
+ local function columns (name: string, cell: Base.Cell): Fields
127
+ local fields = cell.children :: { [string]: Base.Cell }
128
+ local names = Order.names (fields)
129
+ local reach = #names
130
+
131
+ local built = table.create (reach) :: { Shape.Built }
132
+ local place: { [string]: number } = {}
133
+ local newest: { number } = {}
134
+ local optional = table.create (reach) :: { boolean }
135
+ local climbs = table.create (reach) :: { boolean }
136
+ local template: { [string]: any } = {}
137
+ local bytes = 0
138
+
139
+ --[[
140
+ One site for the whole set rather than one a field, everything in it numbered from
141
+ nothing. A section is one block over every field and a boundary holds the definition, so
142
+ fields numbering into tables of their own would each start again at one.
143
+ ]]
144
+ local site: Shape.Site = {
145
+ paths = Serial.interner (),
146
+ expected = Serial.interner (),
147
+ sidecar = { refs = {}, slotOf = {}, bears = false },
148
+ }
149
+
150
+ for index, field in names do
151
+ local held = fields[field]
152
+ local one = Shape.build (Base.codec (held), Serial.under (name, field), site)
153
+
154
+ built[index] = one
155
+ place[field] = index
156
+ bytes += one.maxBytes
157
+ template[field] = PLACE
158
+ optional[index] = held.kind == "optional"
159
+ climbs[index] = held.marker == "monotonic"
160
+
161
+ if held.marker == "newest" then table.insert (newest, index) end
162
+ end
163
+
164
+ return {
165
+ names = table.freeze (names),
166
+ index = table.freeze (place),
167
+ built = table.freeze (built),
168
+ newest = table.freeze (newest),
169
+ optional = table.freeze (optional),
170
+ climbs = table.freeze (climbs),
171
+ template = table.freeze (template),
172
+ site = site,
173
+ bytes = bytes,
174
+ }
175
+ end
176
+
177
+ -- One declaration as the record it becomes, at the id and under the count it was given.
178
+ local function made (name: string, id: number, over: number, of: Legality.Declared): Def
179
+ local at = of.at
180
+
181
+ if of.kind == "packet" then
182
+ local built = Shape.build (of.of, name)
183
+ local lane = Legality.delivery (of)
184
+
185
+ --[[
186
+ A newest packet's block is a different form rather than the same one differently filled:
187
+ it carries a sequence and never a continuation, because its senders coalesce to one
188
+ value before it is sequenced and a bit saying so would never be anything else.
189
+ ]]
190
+ local head = if lane == "newest"
191
+ then Frames.newest (over, of.isTimestamped)
192
+ else Frames.packet (over, of.isTimestamped)
193
+
194
+ local bytes = Frames.block (head, built.maxBytes)
195
+ Legality.block (name, of, bytes)
196
+
197
+ return table.freeze ({
198
+ id = id,
199
+ name = name,
200
+ kind = "packet" :: "packet",
201
+ maxBytes = built.maxBytes,
202
+ file = at.file,
203
+ line = at.line,
204
+ built = built,
205
+ head = head,
206
+ blockBytes = bytes,
207
+ delivery = lane,
208
+ hz = of.hz,
209
+ timestamped = of.isTimestamped,
210
+ })
211
+ end
212
+
213
+ --[[
214
+ A query is two blocks at two ids, so it is two heads, and what one costs is the wider of
215
+ them. Neither is held to a ceiling: both ride the reliable lane, which is never split and is
216
+ bounded by the budget rather than by what one fire carries.
217
+ ]]
218
+ if of.kind == "query" then
219
+ local request = Shape.build (of.of, Serial.under (name, Legality.REQUEST))
220
+ local response = Shape.build (of.reply, Serial.under (name, Legality.RESPONSE))
221
+
222
+ local asks = Frames.request (over)
223
+ local answers = Frames.response (over)
224
+
225
+ return table.freeze ({
226
+ id = id,
227
+ name = name,
228
+ kind = "query" :: "query",
229
+ maxBytes = math.max (request.maxBytes, response.maxBytes),
230
+ file = at.file,
231
+ line = at.line,
232
+ request = request,
233
+ response = response,
234
+ asks = asks,
235
+ answers = answers,
236
+ blockBytes = math.max (
237
+ Frames.block (asks, request.maxBytes),
238
+ Frames.block (answers, response.maxBytes)
239
+ ),
240
+ })
241
+ end
242
+
243
+ local cell = Base.cell (of.of)
244
+ local held = columns (name, cell)
245
+ local key = of.keyField
246
+
247
+ return table.freeze ({
248
+ id = id,
249
+ name = name,
250
+ kind = "set" :: "set",
251
+ maxBytes = held.bytes,
252
+ file = at.file,
253
+ line = at.line,
254
+ cell = cell,
255
+ head = Frames.section (over),
256
+ stream = Frames.stream (over, #held.names),
257
+ keyField = key,
258
+ keyIndex = if key == nil then nil else held.index[key],
259
+ fieldNames = held.names,
260
+ fieldIndex = held.index,
261
+ fieldBuilt = held.built,
262
+ site = held.site,
263
+ fieldCount = #held.names,
264
+ newestFields = held.newest,
265
+ optionalFields = held.optional,
266
+ climbingFields = held.climbs,
267
+ template = held.template,
268
+ })
269
+ end
270
+
271
+ -- A definition as the descriptor writes it.
272
+ local function framed (of: Def): Serial.Frame
273
+ if of.kind == "packet" then
274
+ return {
275
+ kind = "packet",
276
+ of = of.built,
277
+ delivery = of.delivery,
278
+ hz = of.hz,
279
+ timestamped = of.timestamped,
280
+ }
281
+ end
282
+
283
+ if of.kind == "query" then return { kind = "query", of = of.request, reply = of.response } end
284
+ return { kind = "set", of = { cell = of.cell }, keyField = of.keyField }
285
+ end
286
+
287
+ -- Public --------------------------------------------------------------
288
+
289
+ -- A namespace's declarations, refused or compiled, as one frozen record.
290
+ function Compile.build (space: string, specs: Types.Definitions): Compiled
291
+ local why = Legality.named (space)
292
+ if why ~= nil then Log.refuse (`the namespace {space} {why}`) end
293
+
294
+ local names = Order.names (specs)
295
+
296
+ -- How many ids there are, before any of them is handed out.
297
+ local over = 0
298
+ for _, name in names do
299
+ over += if declared (specs[name]).kind == "query" then 2 else 1
300
+ end
301
+
302
+ local list = table.create (#names) :: { Def }
303
+ local byName: { [string]: Def } = {}
304
+ local byId: { [number]: Def } = {}
305
+ local frames: { [string]: Serial.Frame } = {}
306
+
307
+ local at = 0
308
+ for _, name in names do
309
+ local of = declared (specs[name])
310
+ Legality.definition (name, of)
311
+
312
+ local def = made (name, at, over, of)
313
+ table.insert (list, def)
314
+ byName[name] = def
315
+ frames[name] = framed (def)
316
+
317
+ byId[at] = def
318
+ if def.kind ~= "query" then
319
+ at += 1
320
+ continue
321
+ end
322
+
323
+ byId[at + 1] = def
324
+ at += 2
325
+ end
326
+
327
+ local descriptor = Serial.namespace (space, frames)
328
+
329
+ return table.freeze ({
330
+ space = space,
331
+ descriptor = descriptor,
332
+ hash = Serial.hash (descriptor),
333
+ count = over,
334
+ list = table.freeze (list),
335
+ byName = table.freeze (byName),
336
+ byId = table.freeze (byId),
337
+ })
338
+ end
339
+
340
+ return table.freeze (Compile)
@@ -0,0 +1,332 @@
1
+ --!strict
2
+ --!optimize 2
3
+ -- A declaration whose value comes apart by a computation, as the leaves it takes and the pair.
4
+
5
+ local Base = require (script.Parent.Parent.codec.Base)
6
+ local Grid = require (script.Parent.Grid)
7
+ local Ir = require (script.Parent.Ir)
8
+ local Joins = require (script.Parent.Joins)
9
+ local Protocol = require (script.Parent.Parent.wire.Protocol)
10
+ local Rotation = require (script.Parent.Rotation)
11
+ local Scalars = require (script.Parent.Parent.codec.Scalars)
12
+
13
+ local Folds = {}
14
+
15
+ -- Types ---------------------------------------------------------------
16
+
17
+ -- What a fold becomes, which is what a field the language carries becomes and for one reason.
18
+ export type Field = Joins.Field
19
+
20
+ -- Constants -----------------------------------------------------------
21
+
22
+ -- What the engine calls each of the four this file takes apart.
23
+ const PLANE = "Vector2"
24
+ const VECTOR = "Vector3"
25
+ const FRAME = "CFrame"
26
+ const COLOUR = "Color3"
27
+
28
+ -- The same four, under the kinds that declare them.
29
+ Folds.ENGINE = table.freeze ({
30
+ vec2 = PLANE,
31
+ vec3 = VECTOR,
32
+ color3 = COLOUR,
33
+ cframe = FRAME,
34
+ })
35
+
36
+ -- The four a smallest three chooses between, which is what its tag is a ranged int over.
37
+ const CORNERS = Protocol.QUAT_W + 1
38
+
39
+ -- How far past its first leaf the last of those four sits.
40
+ const LAST = CORNERS - 1
41
+
42
+ -- What a packed colour spends on each of its three, which is named one at a time.
43
+ const RED = Protocol.RGB565_RED
44
+ const GREEN = Protocol.RGB565_GREEN
45
+ const BLUE = Protocol.RGB565_BLUE
46
+
47
+ -- Private -------------------------------------------------------------
48
+
49
+ -- A fold, as the one shape every form below answers in.
50
+ export type Fold = {
51
+ leaves: { Grid.Grid },
52
+ pull: (value: any, into: { number }, at: number) -> boolean,
53
+ push: (from: { number }, at: number) -> any,
54
+ }
55
+
56
+ -- The components of a vector, one grid each, in the order they are written.
57
+ local function spread (of: Grid.Grid, wide: boolean): Fold
58
+ local toIndex, fromIndex = of.toIndex, of.fromIndex
59
+
60
+ local leaves = if wide then { of, of, of } else { of, of }
61
+
62
+ -- Both widths come through here, so what it is handed is whichever the leaves say it took.
63
+ local wanted = if wide then VECTOR else PLANE
64
+
65
+ local function pull (value: any, into: { number }, at: number): boolean
66
+ if typeof (value) ~= wanted then return false end
67
+
68
+ local x, y = toIndex (value.X), toIndex (value.Y)
69
+ if x == nil or y == nil then return false end
70
+
71
+ if not wide then
72
+ into[at], into[at + 1] = x, y
73
+ return true
74
+ end
75
+
76
+ local z = toIndex (value.Z)
77
+ if z == nil then return false end
78
+
79
+ into[at], into[at + 1], into[at + 2] = x, y, z
80
+ return true
81
+ end
82
+
83
+ local function push (from: { number }, at: number): any
84
+ if not wide then return Vector2.new (fromIndex (from[at]), fromIndex (from[at + 1])) end
85
+ local x, y = fromIndex (from[at]), fromIndex (from[at + 1])
86
+ return Vector3.new (x, y, fromIndex (from[at + 2]))
87
+ end
88
+
89
+ return { leaves = leaves, pull = pull, push = push }
90
+ end
91
+
92
+ -- A direction as the two the octahedral fold keeps, which is `vec3.unit` and nothing else.
93
+ local function pointing (of: Grid.Grid): Fold
94
+ local mapping = Rotation.octahedral (of)
95
+ local plane, sphere = mapping.plane, mapping.sphere
96
+
97
+ local function pull (value: any, into: { number }, at: number): boolean
98
+ if typeof (value) ~= VECTOR then return false end
99
+
100
+ local u, v = plane (value.X, value.Y, value.Z)
101
+ if u == nil or v == nil then return false end
102
+
103
+ into[at], into[at + 1] = u, v
104
+ return true
105
+ end
106
+
107
+ local function push (from: { number }, at: number): any
108
+ return Vector3.new (sphere (from[at], from[at + 1]))
109
+ end
110
+
111
+ return { leaves = { of, of }, pull = pull, push = push }
112
+ end
113
+
114
+ --[[
115
+ A direction and how far it reaches, the one form whose leaves are two grids. The length is
116
+ worked out and never read off the value, so nothing in this file asks a datatype for anything
117
+ but its components.
118
+ ]]
119
+ local function reaching (way: Grid.Grid, far: Grid.Grid): Fold
120
+ local mapping = Rotation.octahedral (way)
121
+ local plane, sphere = mapping.plane, mapping.sphere
122
+ local toIndex, fromIndex = far.toIndex, far.fromIndex
123
+
124
+ --[[
125
+ Where a vector of no length points, which is nowhere and has to be somewhere. The fold
126
+ divides by the sum of the magnitudes, so a zero would reach the grid as no place at all.
127
+ The middle of the square is what it takes, which multiplies back out to the zero it was.
128
+ ]]
129
+ local centre = way.toIndex (0) :: number
130
+
131
+ local function pull (value: any, into: { number }, at: number): boolean
132
+ if typeof (value) ~= VECTOR then return false end
133
+
134
+ local x, y, z = value.X, value.Y, value.Z
135
+ local length = toIndex (math.sqrt (x * x + y * y + z * z))
136
+ if length == nil then return false end
137
+
138
+ --[[
139
+ A vector whose length comes to none, which is every vector shorter than half a step and
140
+ not only the one that arrived as a zero.
141
+ ]]
142
+ if fromIndex (length) == 0 then
143
+ into[at], into[at + 1], into[at + 2] = centre, centre, length
144
+ return true
145
+ end
146
+
147
+ local u, v = plane (x, y, z)
148
+ if u == nil or v == nil then return false end
149
+
150
+ into[at], into[at + 1], into[at + 2] = u, v, length
151
+ return true
152
+ end
153
+
154
+ local function push (from: { number }, at: number): any
155
+ local x, y, z = sphere (from[at], from[at + 1])
156
+ local length = fromIndex (from[at + 2])
157
+
158
+ return Vector3.new (x * length, y * length, z * length)
159
+ end
160
+
161
+ return { leaves = { way, way, far }, pull = pull, push = push }
162
+ end
163
+
164
+ -- A frame that turns about nothing, which occupies no leaves at all.
165
+ local function still (): Fold
166
+ local function pull (): boolean return true end
167
+ local function push (): any return CFrame.identity end
168
+
169
+ return { leaves = {}, pull = pull, push = push }
170
+ end
171
+
172
+ -- A frame as the one number every rotation form here comes back through, which is a quaternion.
173
+ local function turned (leaves: { Grid.Grid }, parts: any, whole: any, reach: number): Fold
174
+ local function pull (value: any, into: { number }, at: number): boolean
175
+ if typeof (value) ~= FRAME then return false end
176
+
177
+ local first, second, third, fourth = parts (value:GetComponents ())
178
+ if first == nil then return false end
179
+
180
+ into[at] = first :: number
181
+ if reach == 1 then return true end
182
+
183
+ if second == nil then return false end
184
+ into[at + 1] = second :: number
185
+ if reach == 2 then return true end
186
+
187
+ if third == nil or fourth == nil then return false end
188
+ into[at + 2], into[at + LAST] = third :: number, fourth :: number
189
+ return true
190
+ end
191
+
192
+ local function push (from: { number }, at: number): any
193
+ local x, y, z, w = whole (from[at], from[at + 1], from[at + 2], from[at + LAST])
194
+ return CFrame.new (0, 0, 0, x, y, z, w)
195
+ end
196
+
197
+ return { leaves = leaves, pull = pull, push = push }
198
+ end
199
+
200
+ -- The three a packed colour spends its sixteen bits on, red first and least.
201
+ local function packed (): Fold
202
+ local red, green, blue = Grid.channel (RED), Grid.channel (GREEN), Grid.channel (BLUE)
203
+
204
+ local function pull (value: any, into: { number }, at: number): boolean
205
+ if typeof (value) ~= COLOUR then return false end
206
+
207
+ local r, g, b = red.toIndex (value.R), green.toIndex (value.G), blue.toIndex (value.B)
208
+ if r == nil or g == nil or b == nil then return false end
209
+
210
+ into[at], into[at + 1], into[at + 2] = r, g, b
211
+ return true
212
+ end
213
+
214
+ local function push (from: { number }, at: number): any
215
+ return Color3.new (
216
+ red.fromIndex (from[at]),
217
+ green.fromIndex (from[at + 1]),
218
+ blue.fromIndex (from[at + 2])
219
+ )
220
+ end
221
+
222
+ return { leaves = { red, green, blue }, pull = pull, push = push }
223
+ end
224
+
225
+ -- One of a list of colours, as where it sits in the list.
226
+ local function chosen (colors: { Color3 }): Fold
227
+ local reach = #colors
228
+ local of = Grid.index (reach)
229
+
230
+ local index: { [string]: number } = {}
231
+ for place, one in colors do
232
+ index[`{one.R},{one.G},{one.B}`] = place - 1
233
+ end
234
+
235
+ local function pull (value: any, into: { number }, at: number): boolean
236
+ if typeof (value) ~= COLOUR then return false end
237
+
238
+ local held = index[`{value.R},{value.G},{value.B}`]
239
+ if held == nil then return false end
240
+
241
+ into[at] = held
242
+ return true
243
+ end
244
+
245
+ local function push (from: { number }, at: number): any return colors[from[at] + 1] end
246
+
247
+ return { leaves = { of }, pull = pull, push = push }
248
+ end
249
+
250
+ -- Public --------------------------------------------------------------
251
+
252
+ -- Which fold a declaration is, or nothing where it is no region field at all.
253
+ function Folds.fold (of: Base.Cell): Fold?
254
+ local kind, params = of.kind, of.params
255
+ local form = params.form
256
+
257
+ if kind == "vec2" or kind == "vec3" then
258
+ local children = of.children
259
+ local component = if children == nil then nil else children.component
260
+
261
+ if form == "unit" then return pointing (Grid.plane (params.step :: number)) end
262
+ if form == "bounded" then
263
+ local max, step = params.max :: number, params.step :: number
264
+ return reaching (Grid.of (-1, 1, step / max), Grid.of (0, max, step))
265
+ end
266
+
267
+ if component == nil then return nil end
268
+
269
+ local single = Joins.grid (component)
270
+ if single == nil then return nil end
271
+
272
+ return spread (single, kind == "vec3")
273
+ end
274
+
275
+ if kind == "rotation" then
276
+ if form == "none" then return still () end
277
+
278
+ local step = params.step :: number
279
+ if form == "axis" then
280
+ local axis = params.axis :: Vector3
281
+ local grid = Grid.of (0, Scalars.TURN - step, step, true)
282
+ local mapping = Rotation.axial (grid, axis.X, axis.Y, axis.Z)
283
+
284
+ return turned ({ grid }, mapping.parts, mapping.whole, 1)
285
+ end
286
+
287
+ if form == "direction" then
288
+ local grid = Grid.plane (step)
289
+ local mapping = Rotation.facing (grid)
290
+
291
+ return turned ({ grid, grid }, mapping.parts, mapping.whole, 2)
292
+ end
293
+
294
+ local chord = Grid.chord (step)
295
+ local mapping = Rotation.smallest (chord)
296
+
297
+ return turned (
298
+ { Grid.index (CORNERS), chord, chord, chord },
299
+ mapping.parts,
300
+ mapping.whole,
301
+ 4
302
+ )
303
+ end
304
+
305
+ if kind ~= "color3" then return nil end
306
+
307
+ if form == "rgb565" then return packed () end
308
+ if form == "palette" then return chosen (params.colors :: { Color3 }) end
309
+
310
+ return nil
311
+ end
312
+
313
+ -- A declaration, at the leaf it starts on, as the field it becomes.
314
+ function Folds.of (of: Base.Cell, tag: Ir.Tag, at: number, key: string?, nest: number?): Field?
315
+ local held = Folds.fold (of)
316
+ if held == nil then return nil end
317
+
318
+ return {
319
+ leaves = held.leaves,
320
+ join = {
321
+ at = at,
322
+ count = #held.leaves,
323
+ key = key,
324
+ nest = nest,
325
+ tag = tag,
326
+ pull = held.pull,
327
+ push = held.push,
328
+ },
329
+ }
330
+ end
331
+
332
+ return table.freeze (Folds)