@effect-vfs/core 0.9.0 → 0.11.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 (106) hide show
  1. package/dist/BytePath.d.ts +4 -1
  2. package/dist/BytePath.d.ts.map +1 -1
  3. package/dist/BytePath.js +6 -4
  4. package/dist/Caller.d.ts +105 -66
  5. package/dist/Caller.d.ts.map +1 -1
  6. package/dist/Caller.js +15 -87
  7. package/dist/LiveVolume.d.ts +14 -8
  8. package/dist/LiveVolume.d.ts.map +1 -1
  9. package/dist/LiveVolume.js +10 -3
  10. package/dist/Search.d.ts +32 -8
  11. package/dist/Search.d.ts.map +1 -1
  12. package/dist/Search.js +14 -13
  13. package/dist/SynchronousAdapter.d.ts +58 -0
  14. package/dist/SynchronousAdapter.d.ts.map +1 -0
  15. package/dist/SynchronousAdapter.js +116 -0
  16. package/dist/Target.d.ts +7 -91
  17. package/dist/Target.d.ts.map +1 -1
  18. package/dist/Target.js +7 -47
  19. package/dist/Testing.d.ts +9 -5
  20. package/dist/Testing.d.ts.map +1 -1
  21. package/dist/Testing.js +3 -2
  22. package/dist/VfsError.d.ts +1 -1
  23. package/dist/VfsError.d.ts.map +1 -1
  24. package/dist/VirtualFileSystem.d.ts +143 -59
  25. package/dist/VirtualFileSystem.d.ts.map +1 -1
  26. package/dist/VirtualFileSystem.js +37 -33
  27. package/dist/Volume.d.ts +6 -1
  28. package/dist/Volume.d.ts.map +1 -1
  29. package/dist/Volume.js +6 -2
  30. package/dist/internal/adapterBinding.d.ts +13 -0
  31. package/dist/internal/adapterBinding.d.ts.map +1 -0
  32. package/dist/internal/adapterBinding.js +13 -0
  33. package/dist/internal/bytePath.d.ts +6 -1
  34. package/dist/internal/bytePath.d.ts.map +1 -1
  35. package/dist/internal/callerWatch.d.ts +5 -1
  36. package/dist/internal/callerWatch.d.ts.map +1 -1
  37. package/dist/internal/callerWatch.js +4 -3
  38. package/dist/internal/engine.d.ts +1305 -0
  39. package/dist/internal/engine.d.ts.map +1 -0
  40. package/dist/internal/engine.js +3458 -0
  41. package/dist/internal/errors.d.ts +1 -33
  42. package/dist/internal/errors.d.ts.map +1 -1
  43. package/dist/internal/errors.js +1 -45
  44. package/dist/internal/fixture.d.ts +3 -2
  45. package/dist/internal/fixture.d.ts.map +1 -1
  46. package/dist/internal/fixture.js +7 -3
  47. package/dist/internal/image.d.ts +4 -1
  48. package/dist/internal/image.d.ts.map +1 -1
  49. package/dist/internal/image.js +6 -3
  50. package/dist/internal/lines.d.ts.map +1 -1
  51. package/dist/internal/lines.js +3 -2
  52. package/dist/internal/liveImage.d.ts +4 -2
  53. package/dist/internal/liveImage.d.ts.map +1 -1
  54. package/dist/internal/liveImage.js +3 -1
  55. package/dist/internal/merkle.d.ts +8 -5
  56. package/dist/internal/merkle.d.ts.map +1 -1
  57. package/dist/internal/merkle.js +8 -7
  58. package/dist/internal/search.d.ts +3 -1
  59. package/dist/internal/search.d.ts.map +1 -1
  60. package/dist/internal/search.js +4 -3
  61. package/dist/internal/snapshotDelta.d.ts +14 -10
  62. package/dist/internal/snapshotDelta.d.ts.map +1 -1
  63. package/dist/internal/snapshotDelta.js +15 -9
  64. package/dist/internal/snapshotMerge.d.ts +1 -1
  65. package/dist/internal/snapshotMerge.d.ts.map +1 -1
  66. package/dist/internal/snapshotMerge.js +5 -2
  67. package/dist/internal/tree.d.ts +4 -2
  68. package/dist/internal/tree.d.ts.map +1 -1
  69. package/dist/internal/tree.js +4 -2
  70. package/dist/internal/virtualFileSystem.d.ts +27 -56
  71. package/dist/internal/virtualFileSystem.d.ts.map +1 -1
  72. package/dist/internal/virtualFileSystem.js +77 -2085
  73. package/dist/internal/volumeLimits.d.ts +1 -0
  74. package/dist/internal/volumeLimits.d.ts.map +1 -1
  75. package/dist/internal/volumeLimits.js +3 -2
  76. package/dist/internal/volumeState.d.ts +10 -79
  77. package/dist/internal/volumeState.d.ts.map +1 -1
  78. package/dist/internal/volumeState.js +9 -79
  79. package/dist/internal/watchHub.d.ts +3 -3
  80. package/dist/internal/watchHub.d.ts.map +1 -1
  81. package/dist/internal/watchHub.js +4 -2
  82. package/package.json +14 -9
  83. package/dist/internal/confinement.d.ts +0 -16
  84. package/dist/internal/confinement.d.ts.map +0 -1
  85. package/dist/internal/confinement.js +0 -79
  86. package/dist/internal/directoryEntries.d.ts +0 -6
  87. package/dist/internal/directoryEntries.d.ts.map +0 -1
  88. package/dist/internal/directoryEntries.js +0 -79
  89. package/dist/internal/inodeTable.d.ts +0 -20
  90. package/dist/internal/inodeTable.d.ts.map +0 -1
  91. package/dist/internal/inodeTable.js +0 -48
  92. package/dist/internal/path.d.ts +0 -56
  93. package/dist/internal/path.d.ts.map +0 -1
  94. package/dist/internal/path.js +0 -141
  95. package/dist/internal/resolution.d.ts +0 -139
  96. package/dist/internal/resolution.d.ts.map +0 -1
  97. package/dist/internal/resolution.js +0 -332
  98. package/dist/internal/testSeams.d.ts +0 -17
  99. package/dist/internal/testSeams.d.ts.map +0 -1
  100. package/dist/internal/testSeams.js +0 -20
  101. package/dist/internal/tokenRegistry.d.ts +0 -83
  102. package/dist/internal/tokenRegistry.d.ts.map +0 -1
  103. package/dist/internal/tokenRegistry.js +0 -146
  104. package/dist/internal/turnstile.d.ts +0 -8
  105. package/dist/internal/turnstile.d.ts.map +0 -1
  106. package/dist/internal/turnstile.js +0 -43
@@ -9,6 +9,7 @@ export declare const defaults: VolumeLimits;
9
9
  /** @internal */
10
10
  export declare const configuration: (options?: VolumeOptions, operation?: string) => Result.Result<{
11
11
  options: {
12
+ readonly execution?: "cooperative" | "sync";
12
13
  readonly identity?: string & import("effect/Brand").Brand<"@effect-vfs/core/VolumeIdentity">;
13
14
  readonly maxEntries?: number;
14
15
  readonly maxPendingOperations?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"volumeLimits.d.ts","sourceRoot":"","sources":["../../src/internal/volumeLimits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjE,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAGtC,KAAK,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAM1C,gBAAgB;AAChB,eAAO,MAAM,QAAQ,EAAE,YAOrB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,aAAa,aAAc,aAAa;;;;;;;;;;;;;;;;;;;4CAelD,CAAA;AAEH,gBAAgB;AAChB,eAAO,MAAM,WAAW,aAAc,aAAa;;;;;;;6CACyB,CAAA;AAE5E,gBAAgB;AAChB,eAAO,MAAM,UAAU,WAAY,YAAY,YAAW,YAAY;;;;;;;6CAerE,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,QAAQ,WAAY,YAAY,KAAG,YAY/C,CAAA;AAKD,gBAAgB;AAChB,eAAO,MAAM,UAAU,WACb,YAAY,aACT,YAAY,YACb,cAAc,sBACJ,cAAc,KACjC,OAGkE,CAAA"}
1
+ {"version":3,"file":"volumeLimits.d.ts","sourceRoot":"","sources":["../../src/internal/volumeLimits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,KAAK,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAGjE,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAMtC,KAAK,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AAM1C,gBAAgB;AAChB,eAAO,MAAM,QAAQ,EAAE,YAOrB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,aAAa,aAAc,aAAa;;;;;;;;;;;;;;;;;;;;4CAelD,CAAA;AAEH,gBAAgB;AAChB,eAAO,MAAM,WAAW,aAAc,aAAa;;;;;;;6CACyB,CAAA;AAE5E,gBAAgB;AAChB,eAAO,MAAM,UAAU,WAAY,YAAY,YAAW,YAAY;;;;;;;6CAerE,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,QAAQ,WAAY,YAAY,KAAG,YAY/C,CAAA;AAKD,gBAAgB;AAChB,eAAO,MAAM,UAAU,WACb,YAAY,aACT,YAAY,YACb,cAAc,sBACJ,cAAc,KACjC,OAGkE,CAAA"}
@@ -1,8 +1,9 @@
1
1
  import * as ByteSize from "effect/ByteSize";
2
2
  import * as Result from "effect/Result";
3
3
  import { VolumeOptions } from "../Volume.js";
4
- import { decodeConfiguration } from "./errors.js";
5
- import { MAX_FILE_BYTES } from "./volumeState.js";
4
+ import { Errors, State } from "./engine.js";
5
+ const decodeConfiguration = Errors.decodeConfiguration;
6
+ const MAX_FILE_BYTES = State.MAX_FILE_BYTES;
6
7
  /** @internal */
7
8
  export const defaults = Object.freeze({
8
9
  maxEntries: undefined,
@@ -1,88 +1,18 @@
1
- import * as Brand from "effect/Brand";
2
1
  import * as Effect from "effect/Effect";
3
- import * as Order from "effect/Order";
4
- import type { Metadata } from "../Metadata.js";
5
- import * as InodeTable from "./inodeTable.js";
2
+ import { State } from "./engine.js";
6
3
  import type { StoredMetadata } from "./metadata.js";
7
- /** @internal */
8
- export type Ino = number & Brand.Brand<"@effect-vfs/core/Ino">;
9
- /** @internal */
10
- export declare const Ino: Brand.Constructor<Ino>;
11
- /** @internal */
12
- export declare const ROOT_INO: Ino;
13
- /** @internal */
14
- export declare const MAX_INO: number;
15
- /** @internal */
16
- export declare const MAX_FILE_BYTES = 4294967295;
17
- /** @internal */
18
- export declare const WALK_YIELD_INTERVAL = 128;
19
- /** @internal */
20
- export interface Link {
21
- readonly parent: Ino;
22
- readonly name: string;
23
- }
24
- /** @internal */
25
- export type NodeMetadata = Omit<Metadata, "revision">;
26
- /** @internal */
27
- export interface Directory {
28
- readonly kind: "directory";
29
- readonly ino: Ino;
30
- readonly parent: Ino;
31
- readonly name: string;
32
- readonly entries: ReadonlyMap<string, Ino>;
33
- readonly metadata: NodeMetadata;
34
- readonly revision: bigint;
35
- }
36
- /** @internal */
37
- export interface RegularFile {
38
- readonly kind: "file";
39
- readonly ino: Ino;
40
- readonly data: Uint8Array;
41
- readonly links: ReadonlyArray<Link>;
42
- readonly metadata: NodeMetadata;
43
- readonly revision: bigint;
44
- }
45
- /** @internal */
46
- export interface SymbolicLink {
47
- readonly kind: "symlink";
48
- readonly ino: Ino;
49
- readonly target: Uint8Array;
50
- readonly links: ReadonlyArray<Link>;
51
- readonly metadata: NodeMetadata;
52
- readonly revision: bigint;
53
- }
54
- /** @internal */
55
- export type Node = Directory | RegularFile | SymbolicLink;
56
- /** @internal */
57
- export interface VolumeState {
58
- readonly inodes: InodeTable.InodeTable<Node>;
59
- readonly open: ReadonlyMap<Ino, number>;
60
- readonly nextInode: Ino;
61
- readonly revision: bigint;
62
- readonly entries: number;
63
- readonly usedBytes: bigint;
64
- }
65
- /** @internal */
66
- export declare const getNode: (state: VolumeState, ino: Ino) => Node | undefined;
67
- /** @internal */
68
- export declare const byIno: Order.Order<Node>;
69
- /** @internal */
70
- export declare const byEntryName: Order.Order<readonly [string, Ino]>;
71
- /** @internal */
72
- export declare const payloadOf: (node: Node) => Uint8Array | undefined;
73
- /** @internal */
74
- export declare const directoryMetadata: (ino: bigint, uid: number, gid: number, mode: number, now: bigint) => NodeMetadata;
75
- /** @internal */
76
- export declare const emptyRoot: (now: bigint) => Directory;
77
- /** @internal */
78
- export declare const emptyState: (now: bigint) => VolumeState;
4
+ declare const Ino: import("effect/Brand").Constructor<State.Ino>;
5
+ type Ino = State.Ino;
6
+ type Link = State.Link;
7
+ type NodeMetadata = State.NodeMetadata;
8
+ type VolumeState = State.VolumeState;
79
9
  /** @internal */
80
10
  export declare const storedMetadata: (metadata: NodeMetadata) => StoredMetadata;
81
11
  /** @internal */
82
- export declare const reachableNodes: (state: VolumeState) => Effect.Effect<Node[], never, never>;
12
+ export declare const reachableNodes: (state: State.VolumeState) => Effect.Effect<State.Node[], never, never>;
83
13
  /** @internal */
84
- export declare const reachableValue: (source: VolumeState) => Effect.Effect<{
85
- state: VolumeState;
14
+ export declare const reachableValue: (source: State.VolumeState) => Effect.Effect<{
15
+ state: State.VolumeState;
86
16
  largestFile: number;
87
17
  }, never, never>;
88
18
  /** @internal */
@@ -110,4 +40,5 @@ export type NodeSpec = {
110
40
  };
111
41
  /** @internal */
112
42
  export declare const assemble: (specs: ReadonlyArray<NodeSpec>) => VolumeState;
43
+ export {};
113
44
  //# sourceMappingURL=volumeState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"volumeState.d.ts","sourceRoot":"","sources":["../../src/internal/volumeState.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"volumeState.d.ts","sourceRoot":"","sources":["../../src/internal/volumeState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,QAAA,MAAQ,GAAG,+CAAsF,CAAA;AAEjG,KAAK,GAAG,GAAG,KAAK,CAAC,GAAG,CAAA;AAEpB,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;AAEtB,KAAK,YAAY,GAAG,KAAK,CAAC,YAAY,CAAA;AAUtC,KAAK,WAAW,GAAG,KAAK,CAAC,WAAW,CAAA;AAEpC,gBAAgB;AAChB,eAAO,MAAM,cAAc,aAAc,YAAY,KAAG,cAQtD,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc,yEAuBzB,CAAA;AAUF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;gBA4BzB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAChB;IACA,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,GACC;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,GACC;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IACjB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B,CAAA;AAMH,gBAAgB;AAChB,eAAO,MAAM,QAAQ,UAAW,aAAa,CAAC,QAAQ,CAAC,KAAG,WAsEzD,CAAA"}
@@ -1,76 +1,8 @@
1
- import * as Brand from "effect/Brand";
2
1
  import * as Effect from "effect/Effect";
2
+ import * as HashMap from "effect/HashMap";
3
3
  import * as Match from "effect/Match";
4
- import * as Order from "effect/Order";
5
- import * as InodeTable from "./inodeTable.js";
6
- /** @internal */
7
- export const Ino = Brand.nominal();
8
- /** @internal */
9
- export const ROOT_INO = Ino(1);
10
- // The largest inode number a value holds. The allocator resumes one above it and must stay exactly representable,
11
- // since the inode table is keyed by a number.
12
- /** @internal */
13
- export const MAX_INO = Number.MAX_SAFE_INTEGER - 1;
14
- // File sizes fit an unsigned 32-bit count in the volume and its public options.
15
- /** @internal */
16
- export const MAX_FILE_BYTES = 0xffffffff;
17
- // Nodes walked between yields. Whole-tree reads are one synchronous tick otherwise, which
18
- // starves the event loop and leaves nothing for interruption to act on.
19
- /** @internal */
20
- export const WALK_YIELD_INTERVAL = 128;
21
- /** @internal */
22
- export const getNode = (state, ino) => InodeTable.get(state.inodes, ino);
23
- /** @internal */
24
- export const byIno = Order.mapInput(Order.Number, (node) => node.ino);
25
- /** @internal */
26
- export const byEntryName = Order.mapInput(Order.String, ([name]) => name);
27
- const inNameOrder = (entries) => {
28
- let previous;
29
- for (const name of entries.keys()) {
30
- if (previous !== undefined && previous > name)
31
- return false;
32
- previous = name;
33
- }
34
- return true;
35
- };
36
- const inEntryOrder = (directory) => inNameOrder(directory.entries)
37
- ? directory
38
- : { ...directory, entries: new Map([...directory.entries].sort(byEntryName)) };
39
- /** @internal */
40
- export const payloadOf = (node) => node.kind === "file" ? node.data : node.kind === "symlink" ? node.target : undefined;
41
- /** @internal */
42
- export const directoryMetadata = (ino, uid, gid, mode, now) => ({
43
- kind: "directory",
44
- ino,
45
- uid,
46
- gid,
47
- mode,
48
- nlink: 2,
49
- size: 0n,
50
- atimeNs: now,
51
- mtimeNs: now,
52
- ctimeNs: now,
53
- birthtimeNs: now
54
- });
55
- /** @internal */
56
- export const emptyRoot = (now) => ({
57
- kind: "directory",
58
- ino: ROOT_INO,
59
- parent: ROOT_INO,
60
- name: "",
61
- entries: new Map(),
62
- metadata: directoryMetadata(BigInt(ROOT_INO), 0, 0, 0o755, now),
63
- revision: 1n
64
- });
65
- /** @internal */
66
- export const emptyState = (now) => ({
67
- inodes: InodeTable.set(InodeTable.empty(), ROOT_INO, emptyRoot(now)),
68
- open: new Map(),
69
- nextInode: Ino(2),
70
- revision: 1n,
71
- entries: 0,
72
- usedBytes: 0n
73
- });
4
+ import { State } from "./engine.js";
5
+ const { Ino, ROOT_INO, WALK_YIELD_INTERVAL, getNode, setNode, byEntryName, inEntryOrder } = State;
74
6
  /** @internal */
75
7
  export const storedMetadata = (metadata) => ({
76
8
  uid: metadata.uid,
@@ -115,13 +47,12 @@ const atFirstRevision = (node) => node.revision === 1n ? node : { ...node, revis
115
47
  /** @internal */
116
48
  export const reachableValue = Effect.fnUntraced(function* (source) {
117
49
  const nodes = yield* reachableNodes(source);
118
- const owner = Symbol();
119
- let inodes = InodeTable.empty();
50
+ const inodes = HashMap.beginMutation(HashMap.empty());
120
51
  let entries = 0;
121
52
  let usedBytes = 0n;
122
53
  let largestFile = 0;
123
54
  for (const node of nodes) {
124
- inodes = InodeTable.set(inodes, node.ino, atFirstRevision(node.kind === "directory" ? inEntryOrder(node) : node), owner);
55
+ setNode(inodes, atFirstRevision(node.kind === "directory" ? inEntryOrder(node) : node));
125
56
  if (node.kind === "directory")
126
57
  entries += node.entries.size;
127
58
  else if (node.kind === "symlink")
@@ -132,7 +63,7 @@ export const reachableValue = Effect.fnUntraced(function* (source) {
132
63
  }
133
64
  }
134
65
  const state = {
135
- inodes,
66
+ inodes: HashMap.endMutation(inodes),
136
67
  open: new Map(),
137
68
  nextInode: source.nextInode,
138
69
  revision: 1n,
@@ -178,8 +109,7 @@ export const assemble = (specs) => {
178
109
  attach(link.parent, link.name, spec.ino);
179
110
  }
180
111
  }
181
- const owner = Symbol();
182
- let inodes = InodeTable.empty();
112
+ const inodes = HashMap.beginMutation(HashMap.empty());
183
113
  for (const spec of specs) {
184
114
  const base = { ...spec.metadata, ino: BigInt(spec.ino) };
185
115
  const node = Match.value(spec).pipe(Match.discriminator("kind")("directory", (directory) => ({
@@ -205,7 +135,7 @@ export const assemble = (specs) => {
205
135
  metadata: { ...base, kind: "symlink", nlink: symlink.links.length, size: BigInt(symlink.target.length) },
206
136
  revision: symlink.revision
207
137
  })), Match.exhaustive);
208
- inodes = InodeTable.set(inodes, spec.ino, node, owner);
138
+ setNode(inodes, node);
209
139
  }
210
- return { inodes, open: new Map(), nextInode, revision, entries, usedBytes };
140
+ return { inodes: HashMap.endMutation(inodes), open: new Map(), nextInode, revision, entries, usedBytes };
211
141
  };
@@ -2,8 +2,8 @@ import * as Effect from "effect/Effect";
2
2
  import * as Scope from "effect/Scope";
3
3
  import * as Stream from "effect/Stream";
4
4
  /** @internal */
5
- export interface Coordinator {
6
- <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
5
+ export interface Coordinator<Failure> {
6
+ <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | Failure, R>;
7
7
  }
8
8
  /**
9
9
  * Selection callbacks share the context of their publication.
@@ -25,5 +25,5 @@ export interface WatchHub<A, C, E = never> {
25
25
  readonly subscribe: <F extends E = never>(select: Effect.Effect<Selection<A, C, F>, E>, afterSubscribe: Effect.Effect<void>) => Effect.Effect<Stream.Stream<A, F>, E, Scope.Scope>;
26
26
  }
27
27
  /** @internal */
28
- export declare const make: <A, C, E = never>(coordinate: Coordinator, capacity: number) => Effect.Effect<WatchHub<A, C, E>, never, never>;
28
+ export declare const make: <A, C, E = never>(coordinate: Coordinator<E>, capacity: number, synchronous?: boolean | undefined) => Effect.Effect<WatchHub<A, C, E>, never, never>;
29
29
  //# sourceMappingURL=watchHub.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"watchHub.d.ts","sourceRoot":"","sources":["../../src/internal/watchHub.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,gBAAgB;AAChB,MAAM,WAAW,WAAW;IAC1B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;CAClE;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK;IAExC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAA;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;IAElC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAC1D;AAED,gBAAgB;AAChB,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK;IACvC,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;IACvE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5C,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CACxD;AAQD,gBAAgB;AAChB,eAAO,MAAM,IAAI,GAA+B,CAAC,EAAE,CAAC,EAAE,CAAC,sGAoHrD,CAAA"}
1
+ {"version":3,"file":"watchHub.d.ts","sourceRoot":"","sources":["../../src/internal/watchHub.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,gBAAgB;AAChB,MAAM,WAAW,WAAW,CAAC,OAAO;IAClC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;CAC5E;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK;IAExC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAA;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;IAElC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAC1D;AAED,gBAAgB;AAChB,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK;IACvC,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;IACvE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,EACtC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAC5C,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CACxD;AAQD,gBAAgB;AAChB,eAAO,MAAM,IAAI,GAA+B,CAAC,EAAE,CAAC,EAAE,CAAC,4IAwHrD,CAAA"}
@@ -5,7 +5,7 @@ import * as Queue from "effect/Queue";
5
5
  import * as Scope from "effect/Scope";
6
6
  import * as Stream from "effect/Stream";
7
7
  /** @internal */
8
- export const make = Effect.fnUntraced(function* (coordinate, capacity) {
8
+ export const make = Effect.fnUntraced(function* (coordinate, capacity, synchronous = false) {
9
9
  const subscribers = new Set();
10
10
  const offer = (subscriber, event, context) => {
11
11
  const size = Queue.sizeUnsafe(subscriber.queue);
@@ -65,7 +65,9 @@ export const make = Effect.fnUntraced(function* (coordinate, capacity) {
65
65
  const subscriber = registered;
66
66
  if (subscriber === undefined)
67
67
  return Effect.void;
68
- return coordinate(Effect.sync(() => subscribers.delete(subscriber))).pipe(Effect.andThen(Queue.shutdown(subscriber.queue)));
68
+ const remove = Effect.sync(() => subscribers.delete(subscriber));
69
+ // Sync teardown is a known release action: it cannot wait on an active namespace operation.
70
+ return Effect.ensuring(synchronous ? remove : coordinate(remove), Queue.shutdown(subscriber.queue)).pipe(Effect.orDie);
69
71
  }));
70
72
  const closed = () => Predicate.isTagged(scope.state, "Closed");
71
73
  const subscriber = yield* coordinate(Effect.gen(function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-vfs/core",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "A runtime-neutral virtual filesystem core for Effect.",
5
5
  "homepage": "https://github.com/lloydrichards/effect-virtual-fs#readme",
6
6
  "bugs": {
@@ -19,22 +19,23 @@
19
19
  "module": "./dist/index.js",
20
20
  "types": "./dist/index.d.ts",
21
21
  "scripts": {
22
- "build": "tsc --project tsconfig.build.json && tsc --project compatibility/node-next/tsconfig.json",
22
+ "build": "bun run check:engine-imports && tsc --project tsconfig.build.json && tsc --project compatibility/node-next/tsconfig.json",
23
+ "check:engine-imports": "bun compatibility/engine-imports/check.mjs",
23
24
  "clean": "git clean -xdf .cache .turbo dist docs node_modules tsconfig.tsbuildinfo",
24
25
  "test": "bun --bun run vitest run --config ../../vitest.config.ts --project core",
25
26
  "type-check": "tsc --noEmit && tsc --project contracts/tsconfig.json && tsc --project tsconfig.benchmarks.json",
26
27
  "benchmark": "bun --bun run vitest bench --run --config ../../vitest.config.ts --project 'core (bench)'"
27
28
  },
28
29
  "peerDependencies": {
29
- "effect": "^4.0.0"
30
+ "effect": "~4.1.4"
30
31
  },
31
32
  "devDependencies": {
32
- "@effect/platform-bun": "4.0.0",
33
- "@effect/platform-node-shared": "4.0.0",
34
- "@effect/vitest": "4.0.0",
33
+ "@effect/platform-bun": "4.1.4",
34
+ "@effect/platform-node-shared": "4.1.4",
35
+ "@effect/vitest": "4.1.4",
35
36
  "@repo/config-typescript": "workspace:*",
36
- "effect": "4.0.0",
37
- "@types/node": "26.6.3"
37
+ "effect": "4.1.4",
38
+ "@types/node": "26.6.6"
38
39
  },
39
40
  "exports": {
40
41
  ".": {
@@ -104,7 +105,11 @@
104
105
  "./internal/*": null,
105
106
  "./index": null,
106
107
  "./*/index": null,
107
- "./package.json": "./package.json"
108
+ "./package.json": "./package.json",
109
+ "./SynchronousAdapter": {
110
+ "types": "./dist/SynchronousAdapter.d.ts",
111
+ "import": "./dist/SynchronousAdapter.js"
112
+ }
108
113
  },
109
114
  "files": [
110
115
  "dist/**",
@@ -1,16 +0,0 @@
1
- import * as Effect from "effect/Effect";
2
- import type { FsFailure } from "../VfsError.js";
3
- import type { OpContext } from "./errors.js";
4
- import { type Ino, type Node } from "./volumeState.js";
5
- /** @internal */
6
- export declare const make: (view: Effect.Effect<(ino: Ino) => Node | undefined>, roots: ReadonlyArray<Ino>) => {
7
- roots: readonly Ino[];
8
- root: Ino;
9
- alive: (op: OpContext, handle?: boolean) => Effect.Effect<undefined, FsFailure, never>;
10
- contains: (node: Node) => Effect.Effect<boolean, never, never>;
11
- check: (node: Node, op: OpContext, handle?: boolean | undefined) => Effect.Effect<void, FsFailure, never>;
12
- path: (ino: Ino) => Effect.Effect<string | undefined, never, never>;
13
- };
14
- /** @internal */
15
- export type Confinement = ReturnType<typeof make>;
16
- //# sourceMappingURL=confinement.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"confinement.d.ts","sourceRoot":"","sources":["../../src/internal/confinement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI,EAAiC,MAAM,kBAAkB,CAAA;AAErF,gBAAgB;AAChB,eAAO,MAAM,IAAI,SAAU,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,SAAS,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC;;;gBAoD9E,SAAS,WAAU,OAAO;qBAErB,IAAI;;;CAuC7B,CAAA;AAED,gBAAgB;AAChB,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAA"}
@@ -1,79 +0,0 @@
1
- import * as Effect from "effect/Effect";
2
- import { ROOT_INO, WALK_YIELD_INTERVAL } from "./volumeState.js";
3
- /** @internal */
4
- export const make = (view, roots) => {
5
- const descends = Effect.fnUntraced(function* (get, ino, root) {
6
- let node = get(ino);
7
- let steps = 0;
8
- while (node?.kind === "directory" && node.metadata.nlink > 0) {
9
- if (node.ino === root)
10
- return true;
11
- if (node.ino === ROOT_INO)
12
- return false;
13
- const parent = get(node.parent);
14
- if (parent?.kind !== "directory" || parent.entries.get(node.name) !== node.ino)
15
- return false;
16
- node = parent;
17
- if (++steps % WALK_YIELD_INTERVAL === 0)
18
- yield* Effect.yieldNow;
19
- }
20
- return false;
21
- });
22
- const aliveIn = Effect.fnUntraced(function* (get, op, handle) {
23
- for (let index = 0; index < roots.length; index++) {
24
- const root = roots[index];
25
- const node = get(root);
26
- if (node?.kind !== "directory" || node.metadata.nlink === 0) {
27
- return yield* op.fail(handle ? "InvalidHandle" : "ClosedCaller");
28
- }
29
- if (index > 0 && !(yield* descends(get, root, roots[index - 1])))
30
- return yield* op.fail("AccessDenied");
31
- }
32
- });
33
- const containsIn = Effect.fnUntraced(function* (get, node) {
34
- const root = roots.at(-1);
35
- if (root === undefined)
36
- return true;
37
- if (node.kind === "directory")
38
- return yield* descends(get, node.ino, root);
39
- for (const link of node.links) {
40
- const parent = get(link.parent);
41
- if (parent?.kind === "directory" && parent.entries.get(link.name) === node.ino &&
42
- (yield* descends(get, parent.ino, root)))
43
- return true;
44
- }
45
- return false;
46
- });
47
- const alive = (op, handle = false) => Effect.flatMap(view, (get) => aliveIn(get, op, handle));
48
- const contains = (node) => Effect.flatMap(view, (get) => containsIn(get, node));
49
- const check = Effect.fnUntraced(function* (node, op, handle = false) {
50
- // Share the current lookup within authorization, never its result between operations.
51
- const get = yield* view;
52
- yield* aliveIn(get, op, handle);
53
- if (!(yield* containsIn(get, node)))
54
- return yield* op.fail("AccessDenied");
55
- });
56
- const path = Effect.fnUntraced(function* (ino) {
57
- const names = [];
58
- const get = yield* view;
59
- let node = get(ino);
60
- let steps = 0;
61
- if (node?.kind !== "directory" || node.metadata.nlink === 0)
62
- return undefined;
63
- const root = roots.at(-1) ?? ROOT_INO;
64
- while (node.ino !== root) {
65
- if (node.ino === ROOT_INO)
66
- return undefined;
67
- names.push(node.name);
68
- const parent = get(node.parent);
69
- if (parent?.kind !== "directory" || parent.metadata.nlink === 0 || parent.entries.get(node.name) !== node.ino) {
70
- return undefined;
71
- }
72
- node = parent;
73
- if (++steps % WALK_YIELD_INTERVAL === 0)
74
- yield* Effect.yieldNow;
75
- }
76
- return "2f" + names.reverse().join("2f");
77
- });
78
- return { roots, root: roots.at(-1) ?? ROOT_INO, alive, contains, check, path };
79
- };
@@ -1,6 +0,0 @@
1
- import type { Ino } from "./volumeState.js";
2
- /** @internal */
3
- export declare const set: (entries: ReadonlyMap<string, Ino>, name: string, ino: Ino) => ReadonlyMap<string, Ino>;
4
- /** @internal */
5
- export declare const remove: (entries: ReadonlyMap<string, Ino>, name: string) => ReadonlyMap<string, Ino>;
6
- //# sourceMappingURL=directoryEntries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"directoryEntries.d.ts","sourceRoot":"","sources":["../../src/internal/directoryEntries.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AA2E3C,gBAAgB;AAChB,eAAO,MAAM,GAAG,YAAa,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,OAAO,GAAG,KAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAYtG,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,MAAM,YAAa,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,KAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAa/F,CAAA"}
@@ -1,79 +0,0 @@
1
- import * as HashMap from "effect/HashMap";
2
- import * as Option from "effect/Option";
3
- import * as InodeTable from "./inodeTable.js";
4
- // Name lookup and insertion order share immutable trees. Deleted slots are compacted once they outnumber live entries.
5
- class DirectoryEntries {
6
- names;
7
- slots;
8
- length;
9
- [Symbol.toStringTag] = "Map";
10
- constructor(names, slots, length) {
11
- this.names = names;
12
- this.slots = slots;
13
- this.length = length;
14
- }
15
- get size() {
16
- return HashMap.size(this.names);
17
- }
18
- get(name) {
19
- const slot = HashMap.get(this.names, name);
20
- return Option.isSome(slot) ? slot.value.ino : undefined;
21
- }
22
- has(name) {
23
- return HashMap.has(this.names, name);
24
- }
25
- *entries() {
26
- for (let index = 0; index < this.length; index++) {
27
- const entry = InodeTable.get(this.slots, index);
28
- if (entry !== undefined)
29
- yield [entry.name, entry.ino];
30
- }
31
- }
32
- *keys() {
33
- for (const [name] of this)
34
- yield name;
35
- }
36
- *values() {
37
- for (const [, ino] of this)
38
- yield ino;
39
- }
40
- [Symbol.iterator]() {
41
- return this.entries();
42
- }
43
- // oxlint-disable-next-line anti-slop/no-unknown-parameters -- ReadonlyMap forwards the opaque callback receiver without inspecting it.
44
- forEach(callback, thisArg) {
45
- for (const [name, ino] of this)
46
- callback.call(thisArg, ino, name, this);
47
- }
48
- }
49
- const fromEntries = (entries) => {
50
- let slots = InodeTable.empty();
51
- let length = 0;
52
- const owner = Symbol();
53
- const names = HashMap.mutate(HashMap.empty(), (mutable) => {
54
- for (const [name, ino] of entries) {
55
- const entry = { name, ino, index: length };
56
- HashMap.set(mutable, name, entry);
57
- slots = InodeTable.set(slots, length, entry, owner);
58
- length++;
59
- }
60
- });
61
- return new DirectoryEntries(names, slots, length);
62
- };
63
- /** @internal */
64
- export const set = (entries, name, ino) => {
65
- const current = entries instanceof DirectoryEntries ? entries : fromEntries(entries);
66
- const existing = HashMap.get(current.names, name);
67
- const index = Option.isSome(existing) ? existing.value.index : current.length;
68
- const entry = { name, ino, index };
69
- return new DirectoryEntries(HashMap.set(current.names, name, entry), InodeTable.set(current.slots, index, entry), Option.isSome(existing) ? current.length : current.length + 1);
70
- };
71
- /** @internal */
72
- export const remove = (entries, name) => {
73
- const current = entries instanceof DirectoryEntries ? entries : fromEntries(entries);
74
- const existing = HashMap.get(current.names, name);
75
- if (Option.isNone(existing))
76
- return current;
77
- const removed = new DirectoryEntries(HashMap.remove(current.names, name), InodeTable.set(current.slots, existing.value.index, undefined), current.length);
78
- return removed.length > removed.size * 2 ? fromEntries(removed) : removed;
79
- };
@@ -1,20 +0,0 @@
1
- /** @internal */
2
- export type Owner = symbol;
3
- interface Slots<A> {
4
- readonly owner: Owner | undefined;
5
- readonly items: Array<Slots<A> | A | undefined>;
6
- }
7
- /** @internal */
8
- export interface InodeTable<A> {
9
- readonly root: Slots<A>;
10
- readonly levels: number;
11
- readonly capacity: number;
12
- }
13
- /** @internal */
14
- export declare const empty: <A>() => InodeTable<A>;
15
- /** @internal */
16
- export declare const get: <A>(table: InodeTable<A>, key: number) => A | undefined;
17
- /** @internal */
18
- export declare const set: <A>(table: InodeTable<A>, key: number, value: A | undefined, owner?: Owner) => InodeTable<A>;
19
- export {};
20
- //# sourceMappingURL=inodeTable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inodeTable.d.ts","sourceRoot":"","sources":["../../src/internal/inodeTable.ts"],"names":[],"mappings":"AAQA,gBAAgB;AAChB,MAAM,MAAM,KAAK,GAAG,MAAM,CAAA;AAE1B,UAAU,KAAK,CAAC,CAAC;IACf,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAA;CAChD;AAED,gBAAgB;AAChB,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,gBAAgB;AAChB,eAAO,MAAM,KAAK,GAAI,CAAC,OAAK,UAAU,CAAC,CAAC,CAA4E,CAAA;AAKpH,gBAAgB;AAChB,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,OAAO,MAAM,KAAG,CAAC,GAAG,SAgB9D,CAAA;AAsBD,gBAAgB;AAChB,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,OAAO,MAAM,SAAS,CAAC,GAAG,SAAS,UAAU,KAAK,KAAG,UAAU,CAAC,CAAC,CAU3G,CAAA"}
@@ -1,48 +0,0 @@
1
- // A 32-way persistent trie. One owner may mutate paths it has already copied within a batch.
2
- const BITS = 5;
3
- const WIDTH = 1 << BITS;
4
- const MASK = WIDTH - 1;
5
- const SHIFTABLE = 0x100000000; // Shifts wrap keys at 2^32 and shift counts at 32.
6
- const MAX_SHIFT = 32;
7
- /** @internal */
8
- export const empty = () => ({ root: { owner: undefined, items: [] }, levels: 1, capacity: WIDTH });
9
- const index = (key, shift) => key < SHIFTABLE && shift < MAX_SHIFT ? (key >>> shift) & MASK : Math.floor(key / 2 ** shift) % WIDTH;
10
- /** @internal */
11
- export const get = (table, key) => {
12
- if (key >= table.capacity)
13
- return undefined;
14
- let node = table.root;
15
- let shift = (table.levels - 1) * BITS;
16
- while (shift > 0) {
17
- const next = node.items[index(key, shift)];
18
- if (next === undefined)
19
- return undefined;
20
- // SAFETY: every slot above the leaf level holds a Slots value or nothing.
21
- node = next;
22
- shift -= BITS;
23
- }
24
- // SAFETY: leaf level slots hold values or nothing.
25
- return node.items[key & MASK];
26
- };
27
- const setIn = (node, key, value, shift, owner) => {
28
- const target = owner !== undefined && node.owner === owner ? node : { owner, items: node.items.slice() };
29
- if (shift === 0)
30
- target.items[key & MASK] = value;
31
- else {
32
- const at = index(key, shift);
33
- // SAFETY: every slot above the leaf level holds a Slots value or nothing.
34
- const child = node.items[at] ?? { owner: undefined, items: [] };
35
- target.items[at] = setIn(child, key, value, shift - BITS, owner);
36
- }
37
- return target;
38
- };
39
- /** @internal */
40
- export const set = (table, key, value, owner) => {
41
- let { capacity, levels, root } = table;
42
- while (key >= capacity) {
43
- root = { owner, items: [root] };
44
- levels += 1;
45
- capacity *= WIDTH;
46
- }
47
- return { root: setIn(root, key, value, (levels - 1) * BITS, owner), levels, capacity };
48
- };