@raphy-js/raph 1.0.1-dev.20 → 1.0.1-dev.25
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/dist/{core-CyilRD7s.js → core-CClhT8WR.js} +389 -400
- package/dist/core-cPQWYD4K.cjs +1 -0
- package/dist/debug/api/Raph.cjs +1 -1
- package/dist/debug/api/Raph.js +46 -47
- package/dist/debug/api/RaphFacadeSession.cjs +1 -1
- package/dist/debug/api/RaphFacadeSession.js +85 -89
- package/dist/debug/api/RaphReactivityInstance.cjs +1 -1
- package/dist/debug/api/RaphReactivityInstance.js +27 -30
- package/dist/debug/path/DataPath.cjs +1 -1
- package/dist/debug/path/DataPath.js +198 -202
- package/dist/debug/path/PathRouter.cjs +1 -1
- package/dist/debug/path/PathRouter.js +44 -50
- package/dist/debug/path/RaphKernel.cjs +1 -1
- package/dist/debug/path/RaphKernel.js +257 -228
- package/dist/debug/path/data-path.utils.cjs +1 -1
- package/dist/debug/path/data-path.utils.js +41 -41
- package/dist/debug/path/derived/DerivedRegistry.cjs +1 -1
- package/dist/debug/path/derived/DerivedRegistry.js +52 -66
- package/dist/debug/path/derived/RaphDerivedHandle.cjs +1 -1
- package/dist/debug/path/derived/RaphDerivedHandle.js +19 -22
- package/dist/debug/path/derived/derived-collection.utils.cjs +1 -1
- package/dist/debug/path/derived/derived-collection.utils.js +70 -70
- package/dist/debug/path/meta/MetaController.cjs +1 -1
- package/dist/debug/path/meta/MetaController.js +57 -65
- package/dist/debug/path/meta/RaphMeta.cjs +1 -1
- package/dist/debug/path/meta/RaphMeta.js +26 -32
- package/dist/debug/path/meta/RaphMetaStore.cjs +1 -1
- package/dist/debug/path/meta/RaphMetaStore.js +24 -30
- package/dist/debug/path/storage/AdapterPathStore.cjs +1 -1
- package/dist/debug/path/storage/AdapterPathStore.js +49 -54
- package/dist/debug/path/storage/DefaultDataAdapter.cjs +1 -1
- package/dist/debug/path/storage/DefaultDataAdapter.js +46 -56
- package/dist/debug/path/storage/PathEventHub.cjs +1 -1
- package/dist/debug/path/storage/PathEventHub.js +74 -61
- package/dist/debug/path/storage/PathStore.cjs +1 -1
- package/dist/debug/path/storage/PathStore.js +89 -99
- package/dist/debug/path/storage/createDataDraft.cjs +1 -1
- package/dist/debug/path/storage/createDataDraft.js +24 -28
- package/dist/debug/reactivity/disposal.cjs +1 -0
- package/dist/debug/reactivity/disposal.js +32 -0
- package/dist/debug/reactivity/engine.cjs +1 -1
- package/dist/debug/reactivity/engine.js +787 -392
- package/dist/debug/reactivity/reactive-object.cjs +1 -1
- package/dist/debug/reactivity/reactive-object.js +81 -96
- package/dist/debug/reactivity/scope.cjs +1 -1
- package/dist/debug/reactivity/scope.js +221 -117
- package/dist/debug/reactivity/watch.cjs +1 -1
- package/dist/debug/reactivity/watch.js +1 -1
- package/dist/debug/runtime/RaphRuntime.cjs +1 -1
- package/dist/debug/runtime/RaphRuntime.js +764 -411
- package/dist/debug/runtime/diagnostics/RaphDebug.cjs +1 -1
- package/dist/debug/runtime/diagnostics/RaphDebug.js +90 -100
- package/dist/debug/runtime/ownership/RaphEffectScope.cjs +1 -1
- package/dist/debug/runtime/ownership/RaphEffectScope.js +215 -82
- package/dist/debug/runtime/ownership/RaphNode.cjs +1 -1
- package/dist/debug/runtime/ownership/RaphNode.js +595 -136
- package/dist/debug/runtime/ownership/RaphScope.cjs +1 -1
- package/dist/debug/runtime/ownership/RaphScope.js +203 -68
- package/dist/debug/runtime/phases/RaphFrameLoop.cjs +1 -1
- package/dist/debug/runtime/phases/RaphFrameLoop.js +13 -17
- package/dist/debug/runtime/phases/RaphPhasePipeline.cjs +1 -1
- package/dist/debug/runtime/phases/RaphPhasePipeline.js +618 -357
- package/dist/debug/runtime/phases/RaphPhaseTaskRecord.cjs +1 -0
- package/dist/debug/runtime/phases/RaphPhaseTaskRecord.js +176 -0
- package/dist/debug/runtime/phases/RaphPhaseWatch.cjs +1 -0
- package/dist/debug/runtime/phases/RaphPhaseWatch.js +20 -0
- package/dist/debug/runtime/reactivity/PathHandle.cjs +1 -1
- package/dist/debug/runtime/reactivity/PathHandle.js +50 -60
- package/dist/debug/runtime/reactivity/RaphMetaSource.cjs +1 -1
- package/dist/debug/runtime/reactivity/RaphMetaSource.js +28 -32
- package/dist/debug/runtime/reactivity/RaphSelector.cjs +1 -0
- package/dist/debug/runtime/reactivity/RaphSelector.js +503 -0
- package/dist/debug/runtime/reactivity/RaphWorkGraph.cjs +1 -1
- package/dist/debug/runtime/reactivity/RaphWorkGraph.js +541 -379
- package/dist/debug/runtime/reactivity/RuntimeReactivity.cjs +1 -1
- package/dist/debug/runtime/reactivity/RuntimeReactivity.js +484 -90
- package/dist/debug/runtime/reactivity/RuntimeWatch.cjs +1 -1
- package/dist/debug/runtime/reactivity/RuntimeWatch.js +33 -44
- package/dist/debug/runtime/reactivity/disposal-sweep.utils.cjs +1 -0
- package/dist/debug/runtime/reactivity/disposal-sweep.utils.js +42 -0
- package/dist/entrypoints/runtime.d.ts +2 -1
- package/dist/machine-testing.cjs +1 -1
- package/dist/machine-testing.js +1 -1
- package/dist/machine.cjs +1 -1
- package/dist/machine.js +216 -231
- package/dist/path/RaphKernel.d.ts +24 -0
- package/dist/path/storage/PathEventHub.d.ts +14 -0
- package/dist/path/storage/PathStore.d.ts +4 -4
- package/dist/reactivity/disposal.d.ts +14 -0
- package/dist/reactivity/engine.d.ts +177 -4
- package/dist/reactivity/scope.d.ts +108 -30
- package/dist/runtime/RaphRuntime.d.ts +236 -17
- package/dist/runtime/ownership/RaphEffectScope.d.ts +70 -1
- package/dist/runtime/ownership/RaphNode.d.ts +276 -6
- package/dist/runtime/ownership/RaphScope.d.ts +144 -14
- package/dist/runtime/phases/RaphPhasePipeline.d.ts +202 -28
- package/dist/runtime/phases/RaphPhaseTaskRecord.d.ts +195 -0
- package/dist/runtime/phases/RaphPhaseWatch.d.ts +22 -0
- package/dist/runtime/phases/phase.types.d.ts +83 -4
- package/dist/runtime/reactivity/RaphSelector.d.ts +338 -0
- package/dist/runtime/reactivity/RaphWorkGraph.d.ts +163 -25
- package/dist/runtime/reactivity/RuntimeReactivity.d.ts +258 -10
- package/dist/runtime/reactivity/RuntimeWatch.d.ts +8 -8
- package/dist/runtime/reactivity/disposal-sweep.utils.d.ts +19 -0
- package/dist/runtime/reactivity/runtime-reactivity.types.d.ts +48 -3
- package/package.json +9 -1
- package/dist/core-ugchZNqC.cjs +0 -1
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { OwnedSourceEntry } from '../../reactivity/scope';
|
|
2
|
+
import { RaphScope } from '../ownership/RaphScope';
|
|
3
|
+
import { RuntimeDisposalSweeper, RuntimeSignalWriteTap } from './runtime-reactivity.types';
|
|
4
|
+
import { RuntimeReactivity, RuntimeSignal } from './RuntimeReactivity';
|
|
5
|
+
/**
|
|
6
|
+
* Настройки selector.
|
|
7
|
+
*
|
|
8
|
+
* @typeParam Key — тип ключа и значения source.
|
|
9
|
+
*/
|
|
10
|
+
export interface RaphSelectorOptions<Key> {
|
|
11
|
+
/**
|
|
12
|
+
* Сравнение ключа со значением source вместо SameValueZero. Функция должна
|
|
13
|
+
* быть чистой: один и тот же ответ для одной пары аргументов и никаких
|
|
14
|
+
* чтений реактивных источников. С ней запись в source сравнивает каждый
|
|
15
|
+
* наблюдаемый ключ с прежним и с новым значением и будит только те ключи,
|
|
16
|
+
* чей ответ изменился.
|
|
17
|
+
*/
|
|
18
|
+
readonly equals?: (key: Key, value: Key) => boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Чтение selector: сообщает, совпадает ли ключ с текущим значением source, и
|
|
22
|
+
* подписывает активного потребителя только на этот ключ.
|
|
23
|
+
*
|
|
24
|
+
* @typeParam Key — тип ключа и значения source.
|
|
25
|
+
*/
|
|
26
|
+
export type RaphSelector<Key> = (key: Key) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Компактное описание selector, которое возвращает его toJSON().
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export interface RuntimeSelectorDescription {
|
|
33
|
+
readonly owner: string;
|
|
34
|
+
readonly triggers: number;
|
|
35
|
+
readonly disposed: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Selector одним объектом: запись в списке источников владельца, наблюдатель
|
|
39
|
+
* записей source, индекс triggers по ключам и участник уборки Runtime.
|
|
40
|
+
*
|
|
41
|
+
* Trigger ключа — запись-счётчик графа: потребитель, прочитавший ключ,
|
|
42
|
+
* зависит только от неё, а не от source. Запись в source
|
|
43
|
+
* сдвигает счётчики triggers прежнего и нового ключа, и будятся только их
|
|
44
|
+
* потребители. Ответ чтения всегда вычисляется заново по текущему значению
|
|
45
|
+
* source, поэтому лишнее пробуждение безвредно, а пропущенных не бывает:
|
|
46
|
+
* каждая запись, меняющая ответ ключа, сдвигает его счётчик. Вне группировки
|
|
47
|
+
* сдвиг сразу делает потребителя обязательным к пересчёту, внутри неё остаётся
|
|
48
|
+
* у trigger, пока его не прочитает потребитель. Сдвиги не отменяют друг друга:
|
|
49
|
+
* потребитель ключа, через который batch прошёл туда и обратно, выполняется
|
|
50
|
+
* один лишний раз. Исключение то же, что у обычного signal: потребитель,
|
|
51
|
+
* который сам выполнялся в момент записи вне группировки и которого engine не
|
|
52
|
+
* планирует заново, и читатели такого потребителя (см. `_bump`).
|
|
53
|
+
*
|
|
54
|
+
* Trigger нужен, пока у него есть потребители. Как selector узнаёт, что их не
|
|
55
|
+
* осталось, зависит от ключа.
|
|
56
|
+
*
|
|
57
|
+
* - Ключ-объект или функция. Его trigger снимается вместе с последней связью
|
|
58
|
+
* графа: selector не удерживает объект дольше его потребителей. Цена —
|
|
59
|
+
* cleanup на каждую связь.
|
|
60
|
+
* - Остальные ключи. Связи с их triggers ничем не отличаются от связей с
|
|
61
|
+
* signal, и потребитель не платит за selector ни при создании связи, ни при
|
|
62
|
+
* её снятии. Trigger без потребителей остаётся в индексе до уборки. Уборка
|
|
63
|
+
* идёт при записи в source, которая затрагивает такой ключ; когда индекс
|
|
64
|
+
* вырос вдвое после прошлой уборки; когда Runtime после прошлой уборки
|
|
65
|
+
* освободил не меньше владельцев, чем ключей в индексе; при освобождении
|
|
66
|
+
* владельца selector. Уборка после освобождений, которая ничего не убрала,
|
|
67
|
+
* удваивает срок следующей: освобождения посторонних владельцев стоят
|
|
68
|
+
* selector логарифма от их числа, а не уборки на каждые несколько из них.
|
|
69
|
+
* Удержанный до уборки trigger — одна запись графа и значение ключа;
|
|
70
|
+
* потребителей он не удерживает.
|
|
71
|
+
*
|
|
72
|
+
* Индекс triggers состоит из двух частей. Целые ключи, идущие подряд по
|
|
73
|
+
* возрастанию — ключи строк списка, — лежат в ряду: место ряда принадлежит
|
|
74
|
+
* ключу «начало ряда плюс номер места», и ключ стоит selector одного места
|
|
75
|
+
* массива, без записи `Map` и без хеширования. Все остальные ключи лежат в
|
|
76
|
+
* общем индексе `Map`, который создаётся с первым таким ключом. У ключа ровно
|
|
77
|
+
* один trigger: ключ, попавший в общий индекс, остаётся в нём, и ряд через
|
|
78
|
+
* него не растёт. Место ряда принадлежит ключу, только если сумма начала ряда
|
|
79
|
+
* и номера места равна самому ключу: нецелый ключ места не получает никогда.
|
|
80
|
+
*
|
|
81
|
+
* Запись со своим сравнением обходит сначала ряд по возрастанию ключей, затем
|
|
82
|
+
* общий индекс в порядке первого чтения ключей. В этом порядке она будит
|
|
83
|
+
* потребителей; порядок может измениться и контрактом не является.
|
|
84
|
+
*
|
|
85
|
+
* Поля объявлены через `declare` и присваиваются в constructor в одном
|
|
86
|
+
* порядке: у всех selectors один hidden class.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export declare class RuntimeSelector<Key> implements OwnedSourceEntry, RuntimeSignalWriteTap, RuntimeDisposalSweeper {
|
|
91
|
+
/**
|
|
92
|
+
* Публичное чтение selector; одна функция на весь его lifetime.
|
|
93
|
+
*/
|
|
94
|
+
readonly select: RaphSelector<Key>;
|
|
95
|
+
/**
|
|
96
|
+
* Источник, зарегистрированный у владельца перед этим.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
_previousSource: OwnedSourceEntry | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Ключ-объект текущего отслеживаемого чтения: по нему hook onDependency
|
|
102
|
+
* узнаёт, для какого ключа engine создаёт связь. Вне чтения поле пусто.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
_trackedKey: Key | undefined;
|
|
106
|
+
private readonly _owner;
|
|
107
|
+
private readonly _reactivity;
|
|
108
|
+
private readonly _source;
|
|
109
|
+
private _equals;
|
|
110
|
+
private readonly _dense;
|
|
111
|
+
private _denseBase;
|
|
112
|
+
private _denseCount;
|
|
113
|
+
private _triggers;
|
|
114
|
+
private _scanning;
|
|
115
|
+
private readonly _objectHooks;
|
|
116
|
+
private _growthLimit;
|
|
117
|
+
private _sweptAt;
|
|
118
|
+
private _sweepStride;
|
|
119
|
+
private _disposed;
|
|
120
|
+
/**
|
|
121
|
+
* Место selector среди наблюдателей записи source; ведёт source.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
_tapSlot: number;
|
|
125
|
+
/**
|
|
126
|
+
* Место selector в очереди уборки Runtime; -1, пока selector в ней не стоит.
|
|
127
|
+
* Ведёт Runtime.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
_sweepSlot: number;
|
|
131
|
+
/**
|
|
132
|
+
* Срок selector в очереди уборки Runtime; ведёт Runtime.
|
|
133
|
+
* @internal
|
|
134
|
+
*/
|
|
135
|
+
_sweepDue: number;
|
|
136
|
+
/**
|
|
137
|
+
* Создаёт selector и подключает его к записям source. Регистрацию у
|
|
138
|
+
* владельца и проверку аргументов выполняет вызывающий код.
|
|
139
|
+
*/
|
|
140
|
+
constructor(owner: RaphScope, reactivity: RuntimeReactivity, source: RuntimeSignal<Key>, equals: ((key: Key, value: Key) => boolean) | undefined);
|
|
141
|
+
/**
|
|
142
|
+
* Тег Object.prototype.toString: инструменты, которые обходят только plain
|
|
143
|
+
* objects, принимают selector за неделимое значение и не идут через него в
|
|
144
|
+
* граф Runtime.
|
|
145
|
+
*/
|
|
146
|
+
get [Symbol.toStringTag](): string;
|
|
147
|
+
/**
|
|
148
|
+
* Возвращает компактное описание вместо собственных полей: они ведут к
|
|
149
|
+
* владельцу, Runtime и графу зависимостей.
|
|
150
|
+
*/
|
|
151
|
+
toJSON(): RuntimeSelectorDescription;
|
|
152
|
+
/**
|
|
153
|
+
* Владелец selector как наблюдателя записей source.
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
get _tapOwner(): RaphScope;
|
|
157
|
+
/**
|
|
158
|
+
* Число ключей в индексе triggers: с потребителями и ещё не убранных.
|
|
159
|
+
* @internal
|
|
160
|
+
*/
|
|
161
|
+
_debugTriggerCount(): number;
|
|
162
|
+
/**
|
|
163
|
+
* Отвечает, совпадает ли ключ с текущим значением source, и подписывает
|
|
164
|
+
* активного потребителя на trigger этого ключа. Чтение проверяется как
|
|
165
|
+
* чтение signal владельца selector: тот же lifetime, тот же запрет чужого
|
|
166
|
+
* Runtime и то же правило implicit-зависимостей.
|
|
167
|
+
*
|
|
168
|
+
* Подписка идёт раньше сравнения: потребитель, у которого чтение source или
|
|
169
|
+
* сравнение бросило исключение, всё равно будет разбужен следующей записью.
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
_test(key: Key): boolean;
|
|
173
|
+
/**
|
|
174
|
+
* Сообщает, что запись в source может разбудить потребителей selector.
|
|
175
|
+
* @internal
|
|
176
|
+
*/
|
|
177
|
+
_observesWrites(): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Будит потребителей ключей, чей ответ изменила запись в source. Вызывается
|
|
180
|
+
* signal-ом после того, как новое значение стало видимым, внутри его границы
|
|
181
|
+
* записи. Сбой одного пробуждения не отменяет остальные.
|
|
182
|
+
* @internal
|
|
183
|
+
*/
|
|
184
|
+
_afterSourceWrite(previous: unknown, value: unknown): void;
|
|
185
|
+
/**
|
|
186
|
+
* Убирает triggers без потребителей, когда Runtime после прошлой уборки
|
|
187
|
+
* освободил не меньше владельцев, чем ключей в индексе: при массовом
|
|
188
|
+
* освобождении потребителей индекс пустеет одной уборкой на последнем из
|
|
189
|
+
* них. Вызов до срока стоит одного сравнения.
|
|
190
|
+
*
|
|
191
|
+
* Уборка, которая ничего не убрала, удваивает срок следующей: владельцы,
|
|
192
|
+
* освобождённые за это время, не держали потребителей selector, и чем дольше
|
|
193
|
+
* так продолжается, тем реже selector проверяет индекс. Первая же уборка,
|
|
194
|
+
* которая что-то убрала, возвращает прежний срок. Опустевший selector
|
|
195
|
+
* выходит из уборки Runtime и вернётся в неё с первым новым trigger.
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
_afterOwnerDisposals(disposals: number): number;
|
|
199
|
+
/**
|
|
200
|
+
* Обрабатывает снятие одной связи графа с trigger ключа-объекта. Engine
|
|
201
|
+
* вызывает cleanup связи до того, как вынет её из списка потребителей:
|
|
202
|
+
* связь, оставшаяся в списке единственной, и есть снимаемая, и вместе с ней
|
|
203
|
+
* ключ теряет последнего потребителя. Запись графа при этом не
|
|
204
|
+
* освобождается: её список потребителей в этот момент обходит engine, а без
|
|
205
|
+
* потребителей и без ссылки из индекса она недостижима.
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
_edgeDetached(key: Key): void;
|
|
209
|
+
/**
|
|
210
|
+
* Ищет среди потребителей всех triggers первого, чьего владельца принимает
|
|
211
|
+
* accept, и возвращает этого владельца: implicit-рёбра selector лежат только
|
|
212
|
+
* в графе, как и рёбра Runtime signal.
|
|
213
|
+
* @internal
|
|
214
|
+
*/
|
|
215
|
+
_findConsumerOwner<Context>(accept: (consumerOwner: object, context: Context) => boolean, context: Context): object | undefined;
|
|
216
|
+
/**
|
|
217
|
+
* Освобождает selector как источник владельца: отключает его от записей
|
|
218
|
+
* source и от уборки Runtime и отсоединяет оставшихся потребителей от всех
|
|
219
|
+
* triggers. Сбой одного шага не отменяет остальные. Повторный вызов
|
|
220
|
+
* безопасен.
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
_finalizeSource(): boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Убирает из индекса triggers без потребителей и запоминает, сколько
|
|
226
|
+
* владельцев Runtime освободил к этому моменту. Индекс, в котором
|
|
227
|
+
* потребителей не осталось ни у кого, очищается целиком.
|
|
228
|
+
* @internal
|
|
229
|
+
*/
|
|
230
|
+
_sweep(disposals?: number): void;
|
|
231
|
+
/**
|
|
232
|
+
* Число ключей в обеих частях индекса: с потребителями и ещё не убранных.
|
|
233
|
+
*/
|
|
234
|
+
private _size;
|
|
235
|
+
/**
|
|
236
|
+
* Подписывает активного потребителя на trigger ключа; без потребителя ничего
|
|
237
|
+
* не создаёт. Trigger появляется первым отслеживаемым чтением ключа.
|
|
238
|
+
*/
|
|
239
|
+
private _track;
|
|
240
|
+
/**
|
|
241
|
+
* Создаёт trigger целого ключа на месте `offset` ряда: в конце ряда либо на
|
|
242
|
+
* месте, чей прежний trigger убран. Без активного потребителя ничего не
|
|
243
|
+
* создаёт, и пустой ряд остаётся пустым.
|
|
244
|
+
*/
|
|
245
|
+
private _trackDense;
|
|
246
|
+
/**
|
|
247
|
+
* Подписывает активного потребителя на trigger ключа-объекта: связь с ним
|
|
248
|
+
* получает cleanup, который помнит ключ.
|
|
249
|
+
*/
|
|
250
|
+
private _trackObject;
|
|
251
|
+
/**
|
|
252
|
+
* Убирает triggers без потребителей, когда индекс вырос вдвое после прошлой
|
|
253
|
+
* уборки, и назначает следующий порог роста: цена уборок остаётся
|
|
254
|
+
* постоянной на один новый trigger. С первым trigger подключает selector к
|
|
255
|
+
* уборке Runtime после освобождения владельцев.
|
|
256
|
+
*/
|
|
257
|
+
private _grow;
|
|
258
|
+
/**
|
|
259
|
+
* Будит потребителей прежнего и нового значения source при сравнении
|
|
260
|
+
* SameValueZero: ответ изменился только у этих двух ключей. Trigger нового
|
|
261
|
+
* значения ищется после пробуждения прежнего, которое могло изменить индекс.
|
|
262
|
+
*/
|
|
263
|
+
private _wakePair;
|
|
264
|
+
/**
|
|
265
|
+
* Сдвигает счётчик trigger: его потребители получают invalidation. Trigger
|
|
266
|
+
* без потребителей убирается из индекса здесь.
|
|
267
|
+
*
|
|
268
|
+
* Значение trigger только растёт, поэтому сдвиг нельзя отменить следующим:
|
|
269
|
+
* ключ, через который batch прошёл туда и обратно, остаётся изменённым, пока
|
|
270
|
+
* его не прочитает потребитель.
|
|
271
|
+
*
|
|
272
|
+
* Сдвиг — обычная запись signal. Вне группировки она прямая, и потребителя
|
|
273
|
+
* engine делает обязательным к пересчёту в любом его состоянии: без пометок,
|
|
274
|
+
* помеченного «проверить» записью, которую её batch затем отменил
|
|
275
|
+
* (`direct-write-after-check.spec.ts`), и стоящего на стеке собственной
|
|
276
|
+
* проверки зависимостей, getter которой записал source
|
|
277
|
+
* (`direct-write-during-check.spec.ts`, блок `selector trigger`). Внутри
|
|
278
|
+
* группировки сдвиг откладывается у trigger до первого чтения вместе с
|
|
279
|
+
* записью самого source.
|
|
280
|
+
*
|
|
281
|
+
* Потребителя, который выполняется в момент прямого сдвига, engine помечает
|
|
282
|
+
* как при записи любого signal, и непрочитанного сдвига у trigger для него
|
|
283
|
+
* не остаётся. Runtime планирует заново только phase effect, который читает
|
|
284
|
+
* selector сам. Effect без задачи и computed, вернувший прежнее значение,
|
|
285
|
+
* остаются со старым ответом до следующей записи, которая меняет ответ
|
|
286
|
+
* ключа: пометку записи, пришедшей во время запуска, engine с них снимает.
|
|
287
|
+
* Старый ответ такого computed получает и каждый его читатель — phase effect
|
|
288
|
+
* любой формы регистрации, watch и прямое чтение, — в том числе после
|
|
289
|
+
* собственного повторного запуска. Отложенный сдвиг подтверждала им
|
|
290
|
+
* следующая проверка зависимостей или следующий читатель ключа, прямой —
|
|
291
|
+
* нет; обычный signal на месте selector ведёт себя так же, как прямой сдвиг
|
|
292
|
+
* (тот же файл, блок `selector source written while a consumer of the key
|
|
293
|
+
* runs`; причина в engine — блок `known limitations`).
|
|
294
|
+
*/
|
|
295
|
+
private _bump;
|
|
296
|
+
/**
|
|
297
|
+
* Сравнивает один наблюдаемый ключ с прежним и с новым значением source и
|
|
298
|
+
* будит его потребителей, если ответ изменился. Ответ, который не удалось
|
|
299
|
+
* вычислить, считается изменившимся: потребитель встретит то же исключение
|
|
300
|
+
* в собственном чтении. Сбои копятся в `errors`; возвращается их список.
|
|
301
|
+
*/
|
|
302
|
+
private _wakeChanged;
|
|
303
|
+
/**
|
|
304
|
+
* Возвращает trigger ключа из той части индекса, где лежит ключ. Место ряда
|
|
305
|
+
* с убранным trigger отвечает undefined, как отсутствующий ключ. Место ряда
|
|
306
|
+
* проверяется так же, как при чтении: по нему должен получаться сам ключ.
|
|
307
|
+
*/
|
|
308
|
+
private _find;
|
|
309
|
+
/**
|
|
310
|
+
* Убирает trigger ключа из той части индекса, где лежит ключ.
|
|
311
|
+
*
|
|
312
|
+
* Место ряда остаётся пустым, и ряд не сдвигается, даже когда ключ стоял на
|
|
313
|
+
* его краю: запись, убравшая ключ, стоит одинаково при любой длине ряда.
|
|
314
|
+
* Порядок в ряду наводит уборка, которая и так обходит его целиком. Запись
|
|
315
|
+
* делает это сама в двух случаях: ряд опустел, либо мест в нём стало больше,
|
|
316
|
+
* чем вдвое против допустимого для обрезанного ряда. Во втором случае проход
|
|
317
|
+
* оставляет от ряда меньше половины мест либо переносит его в общий индекс,
|
|
318
|
+
* поэтому его цена ложится на создание убранных мест, а не на записи.
|
|
319
|
+
*/
|
|
320
|
+
private _forget;
|
|
321
|
+
/**
|
|
322
|
+
* Приводит ряд в порядок после того, как из него убраны triggers: опустевший
|
|
323
|
+
* ряд становится пустым, пустые места с краёв срезаются, а ряд, в котором
|
|
324
|
+
* после этого мест больше удвоенного числа занятых плюс запас, целиком
|
|
325
|
+
* переносится в общий индекс. Так ряд занимает память, пропорциональную
|
|
326
|
+
* числу своих ключей, какой бы старый ключ ни остался наблюдаемым.
|
|
327
|
+
*
|
|
328
|
+
* Проход стоит длины ряда, поэтому его вызывают уборка и запись со своим
|
|
329
|
+
* сравнением, которые обходят ряд сами, а запись, убравшая один ключ, —
|
|
330
|
+
* только по правилу из `_forget()`. Пока запись обходит индекс, ряд не
|
|
331
|
+
* сдвигается и не переносится: порядок наведёт сам обход.
|
|
332
|
+
*
|
|
333
|
+
* Срез начала сдвигает начало ряда на число срезанных мест. Ключ первого
|
|
334
|
+
* оставшегося места — целое число, равное этой сумме, поэтому сложение
|
|
335
|
+
* точное.
|
|
336
|
+
*/
|
|
337
|
+
private _settleDense;
|
|
338
|
+
}
|
|
@@ -4,7 +4,7 @@ import { RaphScope } from '../ownership/RaphScope';
|
|
|
4
4
|
import { RaphAggregateSource, RaphStructureCause, RaphWatchInclude, RaphWatchSource, RaphWorkCause, RaphWorkCauseKind } from '../phases/phase.types';
|
|
5
5
|
import { RaphRuntime } from '../RaphRuntime';
|
|
6
6
|
type WorkSink = (cause: RaphWorkCause, key: object, schedule: boolean) => void;
|
|
7
|
-
type WorkEdgeSource =
|
|
7
|
+
type WorkEdgeSource = RaphProducer | RaphNode | RaphRuntime;
|
|
8
8
|
interface WorkEdge {
|
|
9
9
|
readonly sink: WorkSink;
|
|
10
10
|
readonly kind: 'producer' | 'runtime' | 'self' | 'subtree';
|
|
@@ -17,7 +17,7 @@ interface WorkEdgeList {
|
|
|
17
17
|
first?: WorkEdge;
|
|
18
18
|
last?: WorkEdge;
|
|
19
19
|
}
|
|
20
|
-
type CleanupSource =
|
|
20
|
+
type CleanupSource = RaphProducer | RaphNode | RaphAggregate;
|
|
21
21
|
interface CleanupEdge {
|
|
22
22
|
cleanup?: () => void;
|
|
23
23
|
source?: CleanupSource;
|
|
@@ -37,25 +37,70 @@ interface AggregateSubscription {
|
|
|
37
37
|
interface ProducerOptions {
|
|
38
38
|
readonly includeRuntime?: boolean;
|
|
39
39
|
}
|
|
40
|
-
declare const PRODUCER_RECORD: unique symbol;
|
|
41
40
|
/** @internal */
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
export type RaphProducerKind = Extract<RaphWorkCauseKind, 'frame' | 'path' | 'producer'>;
|
|
42
|
+
/**
|
|
43
|
+
* Компактное описание producer, которое возвращает его toJSON(): только
|
|
44
|
+
* примитивы, без ссылок на владельца, Runtime и граф зависимостей.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export interface RaphProducerDescription {
|
|
49
|
+
readonly kind: RaphProducerKind;
|
|
50
|
+
readonly owner: string;
|
|
51
|
+
readonly revision: number;
|
|
52
|
+
readonly disposed: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Runtime-сторона одного granular source: адрес explicit watch, token причины
|
|
56
|
+
* для implicit consumers и носитель последней причины. Runtime signal
|
|
57
|
+
* наследует этот класс и сам является своим producer; остальные handles
|
|
58
|
+
* получают отдельную запись через createProducer() и реестр.
|
|
59
|
+
*
|
|
60
|
+
* Поля объявлены через `declare` и присваиваются в constructor в одном
|
|
61
|
+
* порядке: у всех producers один hidden class, и ни один build target не
|
|
62
|
+
* превращает объявления в вызовы field-helper.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export declare class RaphProducer {
|
|
45
67
|
readonly owner: RaphScope;
|
|
46
|
-
readonly kind:
|
|
68
|
+
readonly kind: RaphProducerKind;
|
|
47
69
|
readonly includeRuntime: boolean;
|
|
48
|
-
subscribers
|
|
49
|
-
memberships
|
|
50
|
-
implicitConsumers
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
transientNext?: RaphProducerRecord;
|
|
70
|
+
subscribers: WorkEdgeList | undefined;
|
|
71
|
+
memberships: CleanupEdgeList | undefined;
|
|
72
|
+
implicitConsumers: Map<RaphNode, number> | undefined;
|
|
73
|
+
source: RaphWatchSource | undefined;
|
|
74
|
+
activate: (() => void | Disposer) | undefined;
|
|
75
|
+
runtimeActivation: Disposer | undefined;
|
|
76
|
+
lastCause: RaphWorkCause | undefined;
|
|
77
|
+
transientNext: RaphProducer | undefined;
|
|
57
78
|
revision: number;
|
|
58
79
|
disposed: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Prototype-бренд producer: `true` у RaphProducer и его наследников. Заменяет
|
|
82
|
+
* `instanceof` там, где причина ищется по token на каждое уведомление
|
|
83
|
+
* implicit consumer. Значение лежит на prototype и не занимает поле экземпляра.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
readonly _isProducer: boolean;
|
|
87
|
+
constructor(owner: RaphScope, kind: RaphProducerKind, includeRuntime: boolean);
|
|
88
|
+
get runtime(): RaphRuntime;
|
|
89
|
+
/**
|
|
90
|
+
* Тег Object.prototype.toString: `[object RaphProducer]`. По нему инструменты,
|
|
91
|
+
* которые копируют и обходят только plain objects, принимают producer за
|
|
92
|
+
* неделимое значение: тестовый runner не клонирует его вместе со всем графом
|
|
93
|
+
* Runtime перед печатью diff. Accessor лежит на prototype.
|
|
94
|
+
*/
|
|
95
|
+
get [Symbol.toStringTag](): string;
|
|
96
|
+
/**
|
|
97
|
+
* Возвращает компактное описание вместо собственных полей. Поля producer
|
|
98
|
+
* ведут к владельцу, Runtime и графу зависимостей: без этого метода
|
|
99
|
+
* JSON.stringify упирался бы в циклы, а печать значения в логах и в diff
|
|
100
|
+
* неуспешной проверки тестового runner-а обходила бы весь граф Runtime.
|
|
101
|
+
* Метод лежит на prototype и не добавляет producer ни поля, ни closure.
|
|
102
|
+
*/
|
|
103
|
+
toJSON(): RaphProducerDescription;
|
|
59
104
|
}
|
|
60
105
|
/** Immutable explicit group of granular sources owned by one Runtime scope. */
|
|
61
106
|
export declare class RaphAggregate {
|
|
@@ -102,6 +147,12 @@ export declare class RaphAggregate {
|
|
|
102
147
|
/** Runtime-only intrusive indexes for granular sources. */
|
|
103
148
|
export declare class RaphWorkGraph {
|
|
104
149
|
private readonly _runtime;
|
|
150
|
+
/**
|
|
151
|
+
* Удерживает форму причины записи значения, пока в isolate нет ни одной
|
|
152
|
+
* живой причины.
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
static _valueCauseShapeAnchor: RaphWorkCause;
|
|
105
156
|
private _selfSubscribers;
|
|
106
157
|
private _subtreeSubscribers;
|
|
107
158
|
private _runtimeSubscribers;
|
|
@@ -116,15 +167,53 @@ export declare class RaphWorkGraph {
|
|
|
116
167
|
private _detachedEdges;
|
|
117
168
|
private _disposed;
|
|
118
169
|
constructor(_runtime: RaphRuntime);
|
|
119
|
-
createProducer(owner: RaphScope, kind?:
|
|
120
|
-
attachProducer<T extends object>(record:
|
|
121
|
-
setProducerActivation(record:
|
|
122
|
-
producerHooks(record:
|
|
170
|
+
createProducer(owner: RaphScope, kind?: RaphProducerKind, options?: ProducerOptions): RaphProducer;
|
|
171
|
+
attachProducer<T extends object>(record: RaphProducer, source: T): T;
|
|
172
|
+
setProducerActivation(record: RaphProducer, activate: () => void | Disposer, activateForRuntime?: boolean): void;
|
|
173
|
+
producerHooks(record: RaphProducer): OwnedSourceHooks;
|
|
174
|
+
/**
|
|
175
|
+
* Возвращает последнюю причину producer, который engine назвал своим token.
|
|
176
|
+
* Token чужого Runtime и значение, не являющееся producer, причины не имеют.
|
|
177
|
+
*
|
|
178
|
+
* Метод вызывается на каждое уведомление implicit consumer, поэтому producer
|
|
179
|
+
* распознаётся prototype-брендом, а Runtime читается у владельца напрямую:
|
|
180
|
+
* без `instanceof` и без accessor.
|
|
181
|
+
*/
|
|
123
182
|
causeForToken(token: unknown): RaphWorkCause | undefined;
|
|
124
183
|
/** Clears mutation-local payloads after engine propagation consumed them. */
|
|
125
184
|
clearTransientCauses(): void;
|
|
126
|
-
notifyProducer(record:
|
|
127
|
-
|
|
185
|
+
notifyProducer(record: RaphProducer, previous?: unknown, value?: unknown, events?: RaphWorkCause['events'], schedule?: boolean, hasReactiveSubscribers?: boolean, includeValues?: boolean): void;
|
|
186
|
+
/**
|
|
187
|
+
* Публикует запись значения producer: форма `notifyProducer()` для причины с
|
|
188
|
+
* `previous` и `value`, без events и с планированием. Так свою запись
|
|
189
|
+
* публикует Runtime signal.
|
|
190
|
+
*
|
|
191
|
+
* Причина создаётся при тех же условиях и с теми же полями. Отличие в цене:
|
|
192
|
+
* у producer с implicit consumers, на который не подписан ни один watch, ни
|
|
193
|
+
* его node, ни поддерево, ни Runtime, причину получают только consumers через
|
|
194
|
+
* `causeForToken()`. Тогда обход подписчиков не начинается: запись не строит
|
|
195
|
+
* массив предков и не выполняет ни одного вызова на каждого из них.
|
|
196
|
+
*
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
199
|
+
_notifyValueWrite(record: RaphProducer, previous: unknown, value: unknown, hasReactiveSubscribers: boolean): void;
|
|
200
|
+
notifyProducerEvents(record: RaphProducer, events: NonNullable<RaphWorkCause['events']>, schedule?: boolean, hasReactiveSubscribers?: boolean): void;
|
|
201
|
+
/**
|
|
202
|
+
* Дешёвая предварительная проверка structural publication: `false` означает,
|
|
203
|
+
* что `notifyNode` для этой node вернётся до создания cause и без побочных
|
|
204
|
+
* эффектов. `true` консервативен и ведёт на полный путь.
|
|
205
|
+
*
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
_hasStructuralDemand(node: RaphNode): boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Сообщает, есть ли хотя бы один runtime-, subtree- или self-подписчик.
|
|
211
|
+
* `true` означает, что `_hasStructuralDemand` может вернуть `true` для
|
|
212
|
+
* какой-то node этого Runtime.
|
|
213
|
+
*
|
|
214
|
+
* @internal
|
|
215
|
+
*/
|
|
216
|
+
_hasNodeSubscribers(): boolean;
|
|
128
217
|
notifyNode(node: RaphNode, kind: Extract<RaphWorkCauseKind, 'structure' | 'touch'>, options?: {
|
|
129
218
|
readonly metadata?: unknown;
|
|
130
219
|
readonly structure?: RaphStructureCause;
|
|
@@ -134,18 +223,67 @@ export declare class RaphWorkGraph {
|
|
|
134
223
|
createAggregate(owner: RaphScope, sources: readonly RaphAggregateSource[]): RaphAggregate;
|
|
135
224
|
subscribe(input: RaphWatchSource, include: RaphWatchInclude | undefined, sink: WorkSink): () => void;
|
|
136
225
|
assertSubscriptionAllowed(consumer: RaphScope, input: RaphWatchSource): void;
|
|
137
|
-
/**
|
|
226
|
+
/**
|
|
227
|
+
* Rejects a move that would make an existing implicit reactive edge illegal.
|
|
228
|
+
*
|
|
229
|
+
* Рёбра от producers с отдельной записью (computed, machine) берутся из
|
|
230
|
+
* учёта `implicitConsumers`. Рёбра от Runtime signals нигде не учитываются:
|
|
231
|
+
* они читаются из графа в момент проверки.
|
|
232
|
+
*/
|
|
138
233
|
assertReparentAllowed(node: RaphNode, newParent: RaphNode): void;
|
|
234
|
+
/**
|
|
235
|
+
* Проверяет живые implicit-рёбра от Runtime signals. Implicit-чтение
|
|
236
|
+
* разрешено только у собственного владельца, его предков и root scope,
|
|
237
|
+
* поэтому внешний для переносимого поддерева источник всегда принадлежит
|
|
238
|
+
* прежнему предку `node`. Предок, который остаётся предком нового parent,
|
|
239
|
+
* сохраняет все свои рёбра законными. Остаются предки от прежнего parent до
|
|
240
|
+
* ближайшего общего с новым parent, не включая его: перенос запрещён, если
|
|
241
|
+
* signal такого предка читает потребитель из переносимого поддерева.
|
|
242
|
+
*
|
|
243
|
+
* Посылка о прежнем предке держится на проверке самого чтения: Runtime
|
|
244
|
+
* signal отклоняет implicit-чтение чужого владельца и тогда, когда общий
|
|
245
|
+
* контекст владельца снят untracked-работой другого Runtime, а потребитель
|
|
246
|
+
* этого Runtime остался активным (assertReadable в RuntimeReactivity).
|
|
247
|
+
*
|
|
248
|
+
* Цена переноса. Перенос под прежнего parent и перенос корня дерева
|
|
249
|
+
* проверки не требуют. Иначе для каждого покидаемого предка обходится весь
|
|
250
|
+
* список его источников (не-signals пропускаются за один шаг), а у каждого
|
|
251
|
+
* signal с записью графа — список его потребителей до первого потребителя
|
|
252
|
+
* из переносимого поддерева. Итого O(покидаемые предки × их источники +
|
|
253
|
+
* потребители их signals), без аллокаций. Цена не зависит от того, сколько
|
|
254
|
+
* рёбер между nodes есть в остальном Runtime, но растёт с числом источников
|
|
255
|
+
* и потребителей у покидаемых предков, даже когда их signals читает только
|
|
256
|
+
* сам владелец: перенос из-под parent с тысячей signals обходит всю тысячу.
|
|
257
|
+
* Прежний учёт рёбер стоил наоборот: ничего для таких signals и обход всех
|
|
258
|
+
* producers Runtime с рёбрами между nodes вместе с их потребителями, где бы
|
|
259
|
+
* в дереве они ни находились.
|
|
260
|
+
*/
|
|
261
|
+
private _assertSignalEdgesAllowReparent;
|
|
139
262
|
releaseNode(node: RaphNode): void;
|
|
140
263
|
dispose(): void;
|
|
141
|
-
|
|
264
|
+
/**
|
|
265
|
+
* Освобождает producer: публикует финальную structural cause при спросе и
|
|
266
|
+
* снимает его подписчиков, memberships и регистрацию. Вызывается hook-ом
|
|
267
|
+
* onDispose owned-источника и самим Runtime signal.
|
|
268
|
+
*
|
|
269
|
+
* @internal
|
|
270
|
+
*/
|
|
271
|
+
_disposeProducer(record: RaphProducer, hasReactiveSubscribers?: boolean): void;
|
|
142
272
|
private _dispatchProducer;
|
|
143
273
|
private _dispatchProducerLazily;
|
|
144
274
|
private _createProducerCause;
|
|
145
275
|
private _retainRuntimeSubscriber;
|
|
146
276
|
private _releaseRuntimeSubscriber;
|
|
147
277
|
private _releaseRuntimeActivations;
|
|
148
|
-
|
|
278
|
+
/**
|
|
279
|
+
* Учитывает одно фактическое implicit-ребро графа от producer к consumer
|
|
280
|
+
* owner и возвращает его точное снятие. Вызывается hook-ом onDependency
|
|
281
|
+
* producers с отдельной записью; Runtime signal этого hook не имеет, и его
|
|
282
|
+
* рёбра проверка reparent читает прямо из графа.
|
|
283
|
+
*
|
|
284
|
+
* @internal
|
|
285
|
+
*/
|
|
286
|
+
_linkImplicitDependency(record: RaphProducer, consumerOwner: object): (() => void) | undefined;
|
|
149
287
|
private _subscribeOne;
|
|
150
288
|
private _subscribeNode;
|
|
151
289
|
private _createNodeEdgeRelease;
|