1/**
2 * Transactional hash sets for storing unique values inside Effect
3 * transactions.
4 *
5 * A `TxHashSet` keeps an immutable `HashSet` inside a `TxRef`, so membership
6 * checks and updates can commit atomically with other transactional operations.
7 * Use it when several pieces of shared transactional state must change
8 * together, such as adding a value only after checking related state. The
9 * module includes the usual set operations, including adding, removing,
10 * membership checks, set algebra, mapping, filtering, reducing, and conversion
11 * back to `HashSet`.
12 *
13 * @since 2.0.0
14 */
15
16import * as Effect from "./Effect.ts"
17import { format } from "./Formatter.ts"
18import { dual } from "./Function.ts"
19import * as HashSet from "./HashSet.ts"
20import type { Inspectable } from "./Inspectable.ts"
21import { NodeInspectSymbol, toJson } from "./Inspectable.ts"
22import type { Pipeable } from "./Pipeable.ts"
23import { pipeArguments } from "./Pipeable.ts"
24import { hasProperty, type Predicate, type Refinement } from "./Predicate.ts"
25import * as TxRef from "./TxRef.ts"
26import type { NoInfer } from "./Types.ts"
27
28const TypeId = "~effect/TxHashSet"
29
30const TxHashSetProto = {
31 [TypeId]: TypeId,
32 [NodeInspectSymbol](this: TxHashSet<unknown>) {
33 return toJson(this)
34 },
35 toString(this: TxHashSet<unknown>) {
36 return `TxHashSet(${format(toJson((this).ref))})`
37 },
38 toJSON(this: TxHashSet<unknown>) {
39 return {
40 _id: "TxHashSet",
41 ref: toJson((this).ref)
42 }
43 },
44 pipe(this: TxHashSet<unknown>) {
45 return pipeArguments(this, arguments)
46 }
47}
48
49/**
50 * A TxHashSet is a transactional hash set data structure that provides atomic operations on unique values within Effect transactions. It uses an immutable HashSet internally with TxRef for transactional semantics, ensuring all operations are performed atomically.
51 *
52 * **Details**
53 *
54 * Mutation operations such as `add`, `remove`, and `clear` update the original TxHashSet and return `Effect<void>` or `Effect<boolean>`. Transform operations such as `union`, `intersection`, `difference`, `map`, and `filter` create new TxHashSet instances and leave the original TxHashSet unchanged.
55 *
56 * **Example** (Using transactional hash sets)
57 *
58 * ```ts import.meta.vitest
59 * import { Effect, TxHashSet } from "effect"
60 *
61 * const program = Effect.gen(function*() {
62 * // Create a transactional hash set
63 * const txSet = yield* TxHashSet.make("apple", "banana", "cherry")
64 *
65 * // Single operations are automatically transactional
66 * yield* TxHashSet.add(txSet, "grape")
67 * yield* TxHashSet.has(txSet, "apple") // => true
68 *
69 * // Multi-step atomic operations
70 * yield* Effect.tx(
71 * Effect.gen(function*() {
72 * const hasCherry = yield* TxHashSet.has(txSet, "cherry")
73 * if (hasCherry) {
74 * yield* TxHashSet.remove(txSet, "cherry")
75 * yield* TxHashSet.add(txSet, "orange")
76 * }
77 * })
78 * )
79 *
80 * yield* TxHashSet.size(txSet) // => 4
81 * })
82 *
83 * await Effect.runPromise(program)
84 * ```
85 *
86 * @category models
87 * @since 4.0.0
88 */
89export interface TxHashSet<in out V> extends Inspectable, Pipeable {
90 readonly [TypeId]: typeof TypeId
91 readonly ref: TxRef.TxRef<HashSet.HashSet<V>>
92}
93
94/**
95 * The TxHashSet namespace contains type-level utilities and helper types
96 * for working with TxHashSet instances.
97 *
98 * **Example** (Extracting value types inside transactions)
99 *
100 * ```ts import.meta.vitest
101 * import { Effect, TxHashSet } from "effect"
102 *
103 * const program = Effect.gen(function*() {
104 * // Create a transactional color set
105 * const colors = yield* TxHashSet.make("red", "green", "blue")
106 *
107 * // Extract the value type for reuse
108 * type Color = TxHashSet.TxHashSet.Value<typeof colors> // string
109 *
110 * // Use extracted type in functions
111 * const addColor = (color: Color) => TxHashSet.add(colors, color)
112 *
113 * yield* addColor("yellow")
114 * yield* TxHashSet.has(colors, "yellow") // => true
115 * })
116 *
117 * await Effect.runPromise(program)
118 * ```
119 *
120 * @since 4.0.0
121 */
122export declare namespace TxHashSet {
123 /**
124 * Extracts the value type from a `TxHashSet` type.
125 *
126 * **Example** (Extracting a TxHashSet value type)
127 *
128 * ```ts import.meta.vitest
129 * import type { TxHashSet } from "effect"
130 *
131 * type FruitSet = TxHashSet.TxHashSet<"apple" | "banana" | "cherry">
132 *
133 * // Extract the value type
134 * type Fruit = TxHashSet.TxHashSet.Value<FruitSet> // "apple" | "banana" | "cherry"
135 *
136 * const processFruit = (fruit: Fruit) => {
137 * return `Processing ${fruit}`
138 * }
139 *
140 * processFruit("apple") // => "Processing apple"
141 * ```
142 *
143 * @category utility types
144 * @since 4.0.0
145 */
146 export type Value<T> = T extends TxHashSet<infer V> ? V : never
147}
148
149const makeTxHashSet = <V>(ref: TxRef.TxRef<HashSet.HashSet<V>>): TxHashSet<V> => {
150 const self = Object.create(TxHashSetProto)
151 self.ref = ref
152 return self
153}
154
155/**
156 * Creates an empty TxHashSet.
157 *
158 * **Example** (Creating an empty transactional hash set)
159 *
160 * ```ts import.meta.vitest
161 * import { Effect, TxHashSet } from "effect"
162 *
163 * const program = Effect.gen(function*() {
164 * const txSet = yield* TxHashSet.empty<string>()
165 *
166 * yield* TxHashSet.size(txSet) // => 0
167 * yield* TxHashSet.isEmpty(txSet) // => true
168 *
169 * // Add some values
170 * yield* TxHashSet.add(txSet, "hello")
171 * yield* TxHashSet.add(txSet, "world")
172 * yield* TxHashSet.size(txSet) // => 2
173 * })
174 *
175 * await Effect.runPromise(program)
176 * ```
177 *
178 * @category constructors
179 * @since 2.0.0
180 */
181export const empty = <V = never>(): Effect.Effect<TxHashSet<V>> =>
182 Effect.gen(function*() {
183 const ref = yield* TxRef.make(HashSet.empty<V>())
184 return makeTxHashSet(ref)
185 })
186
187/**
188 * Creates a TxHashSet from a variable number of values.
189 *
190 * **Example** (Creating transactional hash sets from values)
191 *
192 * ```ts import.meta.vitest
193 * import { Effect, TxHashSet } from "effect"
194 *
195 * const program = Effect.gen(function*() {
196 * const fruits = yield* TxHashSet.make("apple", "banana", "cherry")
197 * yield* TxHashSet.size(fruits) // => 3
198 *
199 * const numbers = yield* TxHashSet.make(1, 2, 3, 2, 1) // Duplicates ignored
200 * yield* TxHashSet.size(numbers) // => 3
201 *
202 * const mixed = yield* TxHashSet.make("hello", 42, true)
203 * yield* TxHashSet.size(mixed) // => 3
204 * })
205 *
206 * await Effect.runPromise(program)
207 * ```
208 *
209 * @category constructors
210 * @since 2.0.0
211 */
212export const make = <Values extends ReadonlyArray<any>>(
213 ...values: Values
214): Effect.Effect<TxHashSet<Values[number]>> =>
215 Effect.gen(function*() {
216 const hashSet = HashSet.make(...values)
217 const ref = yield* TxRef.make(hashSet)
218 return makeTxHashSet(ref)
219 })
220
221/**
222 * Creates a TxHashSet from an iterable collection of values.
223 *
224 * **Example** (Creating a transactional hash set from an iterable)
225 *
226 * ```ts import.meta.vitest
227 * import { Effect, TxHashSet } from "effect"
228 *
229 * const program = Effect.gen(function*() {
230 * const fromArray = yield* TxHashSet.fromIterable(["a", "b", "c", "b", "a"])
231 * yield* TxHashSet.size(fromArray) // => 3
232 *
233 * const fromSet = yield* TxHashSet.fromIterable(new Set([1, 2, 3]))
234 * yield* TxHashSet.size(fromSet) // => 3
235 *
236 * const fromString = yield* TxHashSet.fromIterable("hello")
237 * Array.from(yield* TxHashSet.toHashSet(fromString)).sort() // => ["e", "h", "l", "o"]
238 * })
239 *
240 * await Effect.runPromise(program)
241 * ```
242 *
243 * @category constructors
244 * @since 2.0.0
245 */
246export const fromIterable = <V>(values: Iterable<V>): Effect.Effect<TxHashSet<V>> =>
247 Effect.gen(function*() {
248 const hashSet = HashSet.fromIterable(values)
249 const ref = yield* TxRef.make(hashSet)
250 return makeTxHashSet(ref)
251 })
252
253/**
254 * Creates a TxHashSet from an existing HashSet.
255 *
256 * **Example** (Creating a transactional hash set from a HashSet)
257 *
258 * ```ts import.meta.vitest
259 * import { Effect, HashSet, TxHashSet } from "effect"
260 *
261 * const program = Effect.gen(function*() {
262 * const hashSet = HashSet.make("x", "y", "z")
263 * const txSet = yield* TxHashSet.fromHashSet(hashSet)
264 *
265 * yield* TxHashSet.size(txSet) // => 3
266 * yield* TxHashSet.has(txSet, "y") // => true
267 *
268 * // Original hashSet is unchanged when txSet is modified
269 * yield* TxHashSet.add(txSet, "w")
270 * HashSet.size(hashSet) // => 3
271 * yield* TxHashSet.size(txSet) // => 4
272 * })
273 *
274 * await Effect.runPromise(program)
275 * ```
276 *
277 * @category constructors
278 * @since 4.0.0
279 */
280export const fromHashSet = <V>(hashSet: HashSet.HashSet<V>): Effect.Effect<TxHashSet<V>> =>
281 Effect.gen(function*() {
282 const ref = yield* TxRef.make(hashSet)
283 return makeTxHashSet(ref)
284 })
285
286/**
287 * Checks whether a value is a TxHashSet.
288 *
289 * **Example** (Checking for a TxHashSet)
290 *
291 * ```ts import.meta.vitest
292 * import { Effect, HashSet, TxHashSet } from "effect"
293 *
294 * const program = Effect.gen(function*() {
295 * const txSet = yield* TxHashSet.make(1, 2, 3)
296 * const hashSet = HashSet.make(1, 2, 3)
297 * const array = [1, 2, 3]
298 *
299 * TxHashSet.isTxHashSet(txSet) // => true
300 * TxHashSet.isTxHashSet(hashSet) // => false
301 * TxHashSet.isTxHashSet(array) // => false
302 * TxHashSet.isTxHashSet(null) // => false
303 * })
304 *
305 * await Effect.runPromise(program)
306 * ```
307 *
308 * @category guards
309 * @since 4.0.0
310 */
311export const isTxHashSet = (u: unknown): u is TxHashSet<unknown> => hasProperty(u, TypeId)
312
313/**
314 * Adds a value to the TxHashSet. If the value already exists, the operation has no effect.
315 *
316 * **Details**
317 *
318 * This function mutates the original TxHashSet by adding the specified value. It does not return a new TxHashSet reference.
319 *
320 * **Example** (Adding values)
321 *
322 * ```ts import.meta.vitest
323 * import { Effect, TxHashSet } from "effect"
324 *
325 * const program = Effect.gen(function*() {
326 * const txSet = yield* TxHashSet.make("a", "b")
327 *
328 * yield* TxHashSet.add(txSet, "c")
329 * yield* TxHashSet.size(txSet) // => 3
330 * yield* TxHashSet.has(txSet, "c") // => true
331 *
332 * // Adding existing value has no effect
333 * yield* TxHashSet.add(txSet, "a")
334 * yield* TxHashSet.size(txSet) // => 3
335 * })
336 *
337 * await Effect.runPromise(program)
338 * ```
339 *
340 * @category mutations
341 * @since 2.0.0
342 */
343export const add: {
344 <V>(value: V): (self: TxHashSet<V>) => Effect.Effect<void>
345 <V>(self: TxHashSet<V>, value: V): Effect.Effect<void>
346} = dual<
347 <V>(value: V) => (self: TxHashSet<V>) => Effect.Effect<void>,
348 <V>(self: TxHashSet<V>, value: V) => Effect.Effect<void>
349>(2, <V>(self: TxHashSet<V>, value: V) => TxRef.update(self.ref, (set) => HashSet.add(set, value)))
350
351/**
352 * Removes a value from the TxHashSet.
353 *
354 * **Details**
355 *
356 * This function mutates the original TxHashSet by removing the specified value. It does not return a new TxHashSet reference.
357 *
358 * **Example** (Removing values)
359 *
360 * ```ts import.meta.vitest
361 * import { Effect, TxHashSet } from "effect"
362 *
363 * const program = Effect.gen(function*() {
364 * const txSet = yield* TxHashSet.make("a", "b", "c")
365 *
366 * yield* TxHashSet.remove(txSet, "b") // => true
367 * yield* TxHashSet.size(txSet) // => 2
368 * yield* TxHashSet.has(txSet, "b") // => false
369 *
370 * // Removing non-existent value returns false
371 * yield* TxHashSet.remove(txSet, "d") // => false
372 * })
373 *
374 * await Effect.runPromise(program)
375 * ```
376 *
377 * @category mutations
378 * @since 2.0.0
379 */
380export const remove: {
381 <V>(value: V): (self: TxHashSet<V>) => Effect.Effect<boolean>
382 <V>(self: TxHashSet<V>, value: V): Effect.Effect<boolean>
383} = dual<
384 <V>(value: V) => (self: TxHashSet<V>) => Effect.Effect<boolean>,
385 <V>(self: TxHashSet<V>, value: V) => Effect.Effect<boolean>
386>(2, <V>(self: TxHashSet<V>, value: V) =>
387 Effect.gen(function*() {
388 const currentSet = yield* TxRef.get(self.ref)
389 const existed = HashSet.has(currentSet, value)
390 if (existed) {
391 yield* TxRef.set(self.ref, HashSet.remove(currentSet, value))
392 }
393 return existed
394 }).pipe(Effect.tx))
395
396/**
397 * Checks whether the TxHashSet contains the specified value.
398 *
399 * **Example** (Checking membership)
400 *
401 * ```ts import.meta.vitest
402 * import { Effect, Equal, Hash, TxHashSet } from "effect"
403 *
404 * const program = Effect.gen(function*() {
405 * const txSet = yield* TxHashSet.make("apple", "banana", "cherry")
406 *
407 * yield* TxHashSet.has(txSet, "apple") // => true
408 * yield* TxHashSet.has(txSet, "grape") // => false
409 *
410 * // Works with any type that implements Equal
411 * class Person implements Equal.Equal {
412 * constructor(readonly name: string) {}
413 *
414 * [Equal.symbol](other: unknown) {
415 * return other instanceof Person && this.name === other.name
416 * }
417 *
418 * [Hash.symbol](): number {
419 * return Hash.string(this.name)
420 * }
421 * }
422 *
423 * const people = yield* TxHashSet.make(new Person("Alice"), new Person("Bob"))
424 * yield* TxHashSet.has(people, new Person("Alice")) // => true
425 * })
426 *
427 * await Effect.runPromise(program)
428 * ```
429 *
430 * @category predicates
431 * @since 2.0.0
432 */
433export const has: {
434 <V>(value: V): (self: TxHashSet<V>) => Effect.Effect<boolean>
435 <V>(self: TxHashSet<V>, value: V): Effect.Effect<boolean>
436} = dual<
437 <V>(value: V) => (self: TxHashSet<V>) => Effect.Effect<boolean>,
438 <V>(self: TxHashSet<V>, value: V) => Effect.Effect<boolean>
439>(2, <V>(self: TxHashSet<V>, value: V) =>
440 Effect.gen(function*() {
441 const set = yield* TxRef.get(self.ref)
442 return HashSet.has(set, value)
443 }))
444
445/**
446 * Returns the number of values in the TxHashSet.
447 *
448 * **Example** (Getting the set size)
449 *
450 * ```ts import.meta.vitest
451 * import { Effect, TxHashSet } from "effect"
452 *
453 * const program = Effect.gen(function*() {
454 * const empty = yield* TxHashSet.empty<string>()
455 * yield* TxHashSet.size(empty) // => 0
456 *
457 * const small = yield* TxHashSet.make("a", "b")
458 * yield* TxHashSet.size(small) // => 2
459 *
460 * const fromIterable = yield* TxHashSet.fromIterable(["x", "y", "z", "x", "y"])
461 * yield* TxHashSet.size(fromIterable) // => 3
462 * })
463 *
464 * await Effect.runPromise(program)
465 * ```
466 *
467 * @category getters
468 * @since 2.0.0
469 */
470export const size = <V>(self: TxHashSet<V>): Effect.Effect<number> =>
471 Effect.gen(function*() {
472 const set = yield* TxRef.get(self.ref)
473 return HashSet.size(set)
474 })
475
476/**
477 * Checks whether the TxHashSet is empty.
478 *
479 * **Example** (Checking whether a set is empty)
480 *
481 * ```ts import.meta.vitest
482 * import { Effect, TxHashSet } from "effect"
483 *
484 * const program = Effect.gen(function*() {
485 * const empty = yield* TxHashSet.empty<string>()
486 * yield* TxHashSet.isEmpty(empty) // => true
487 *
488 * const nonEmpty = yield* TxHashSet.make("a")
489 * yield* TxHashSet.isEmpty(nonEmpty) // => false
490 * })
491 *
492 * await Effect.runPromise(program)
493 * ```
494 *
495 * @category predicates
496 * @since 2.0.0
497 */
498export const isEmpty = <V>(self: TxHashSet<V>): Effect.Effect<boolean> =>
499 Effect.gen(function*() {
500 const set = yield* TxRef.get(self.ref)
501 return HashSet.isEmpty(set)
502 })
503
504/**
505 * Checks whether the TxHashSet is non-empty.
506 *
507 * **Example** (Checking whether a set is non-empty)
508 *
509 * ```ts import.meta.vitest
510 * import { Effect, TxHashSet } from "effect"
511 *
512 * const program = Effect.gen(function*() {
513 * const empty = yield* TxHashSet.empty<string>()
514 * const emptyResult = yield* TxHashSet.isNonEmpty(empty)
515 *
516 * const nonEmpty = yield* TxHashSet.make("a")
517 * const nonEmptyResult = yield* TxHashSet.isNonEmpty(nonEmpty)
518 * return [emptyResult, nonEmptyResult] as const
519 * })
520 *
521 * await Effect.runPromise(program) // => [false, true]
522 * ```
523 *
524 * @category predicates
525 * @since 4.0.0
526 */
527export const isNonEmpty = <V>(self: TxHashSet<V>): Effect.Effect<boolean> =>
528 Effect.map(isEmpty(self), (empty) => !empty)
529
530/**
531 * Removes all values from the TxHashSet.
532 *
533 * **Details**
534 *
535 * This function mutates the original TxHashSet by clearing all values. It does not return a new TxHashSet reference.
536 *
537 * **Example** (Clearing all values)
538 *
539 * ```ts import.meta.vitest
540 * import { Effect, TxHashSet } from "effect"
541 *
542 * const program = Effect.gen(function*() {
543 * const txSet = yield* TxHashSet.make("a", "b", "c")
544 * yield* TxHashSet.size(txSet) // => 3
545 *
546 * yield* TxHashSet.clear(txSet)
547 * yield* TxHashSet.size(txSet) // => 0
548 * yield* TxHashSet.isEmpty(txSet) // => true
549 * })
550 *
551 * await Effect.runPromise(program)
552 * ```
553 *
554 * @category mutations
555 * @since 4.0.0
556 */
557export const clear = <V>(self: TxHashSet<V>): Effect.Effect<void> => TxRef.set(self.ref, HashSet.empty<V>())
558
559/**
560 * Creates the union of two TxHashSets, returning a new TxHashSet.
561 *
562 * **Example** (Combining sets with union)
563 *
564 * ```ts import.meta.vitest
565 * import { Effect, TxHashSet } from "effect"
566 *
567 * const program = Effect.gen(function*() {
568 * const set1 = yield* TxHashSet.make("a", "b")
569 * const set2 = yield* TxHashSet.make("b", "c")
570 * const combined = yield* TxHashSet.union(set1, set2)
571 *
572 * Array.from(yield* TxHashSet.toHashSet(combined)).sort() // => ["a", "b", "c"]
573 * yield* TxHashSet.size(combined) // => 3
574 * })
575 *
576 * await Effect.runPromise(program)
577 * ```
578 *
579 * @category combinators
580 * @since 2.0.0
581 */
582export const union: {
583 <V1>(that: TxHashSet<V1>): <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V1 | V0>>
584 <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>): Effect.Effect<TxHashSet<V0 | V1>>
585} = dual<
586 <V1>(
587 that: TxHashSet<V1>
588 ) => <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V1 | V0>>,
589 <V0, V1>(
590 self: TxHashSet<V0>,
591 that: TxHashSet<V1>
592 ) => Effect.Effect<TxHashSet<V0 | V1>>
593>(2, <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>) =>
594 Effect.gen(function*() {
595 const set1 = yield* TxRef.get(self.ref)
596 const set2 = yield* TxRef.get(that.ref)
597 const combined = HashSet.union(set1, set2)
598 return yield* fromHashSet(combined)
599 }).pipe(Effect.tx))
600
601/**
602 * Creates the intersection of two TxHashSets, returning a new TxHashSet.
603 *
604 * **Example** (Finding common values)
605 *
606 * ```ts import.meta.vitest
607 * import { Effect, TxHashSet } from "effect"
608 *
609 * const program = Effect.gen(function*() {
610 * const set1 = yield* TxHashSet.make("a", "b", "c")
611 * const set2 = yield* TxHashSet.make("b", "c", "d")
612 * const common = yield* TxHashSet.intersection(set1, set2)
613 *
614 * Array.from(yield* TxHashSet.toHashSet(common)).sort() // => ["b", "c"]
615 * yield* TxHashSet.size(common) // => 2
616 * })
617 *
618 * await Effect.runPromise(program)
619 * ```
620 *
621 * @category combinators
622 * @since 2.0.0
623 */
624export const intersection: {
625 <V1>(that: TxHashSet<V1>): <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V1 & V0>>
626 <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>): Effect.Effect<TxHashSet<V0 & V1>>
627} = dual<
628 <V1>(
629 that: TxHashSet<V1>
630 ) => <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V1 & V0>>,
631 <V0, V1>(
632 self: TxHashSet<V0>,
633 that: TxHashSet<V1>
634 ) => Effect.Effect<TxHashSet<V0 & V1>>
635>(2, <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>) =>
636 Effect.gen(function*() {
637 const set1 = yield* TxRef.get(self.ref)
638 const set2 = yield* TxRef.get(that.ref)
639 const common = HashSet.intersection(set1, set2)
640 return yield* fromHashSet(common)
641 }).pipe(Effect.tx))
642
643/**
644 * Creates the difference of two TxHashSets (elements in the first set that are not in the second), returning a new TxHashSet.
645 *
646 * **Example** (Finding values absent from another set)
647 *
648 * ```ts import.meta.vitest
649 * import { Effect, TxHashSet } from "effect"
650 *
651 * const program = Effect.gen(function*() {
652 * const set1 = yield* TxHashSet.make("a", "b", "c")
653 * const set2 = yield* TxHashSet.make("b", "d")
654 * const diff = yield* TxHashSet.difference(set1, set2)
655 *
656 * Array.from(yield* TxHashSet.toHashSet(diff)).sort() // => ["a", "c"]
657 * yield* TxHashSet.size(diff) // => 2
658 * })
659 *
660 * await Effect.runPromise(program)
661 * ```
662 *
663 * @category combinators
664 * @since 2.0.0
665 */
666export const difference: {
667 <V1>(that: TxHashSet<V1>): <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V0>>
668 <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>): Effect.Effect<TxHashSet<V0>>
669} = dual<
670 <V1>(
671 that: TxHashSet<V1>
672 ) => <V0>(self: TxHashSet<V0>) => Effect.Effect<TxHashSet<V0>>,
673 <V0, V1>(
674 self: TxHashSet<V0>,
675 that: TxHashSet<V1>
676 ) => Effect.Effect<TxHashSet<V0>>
677>(2, <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>) =>
678 Effect.gen(function*() {
679 const set1 = yield* TxRef.get(self.ref)
680 const set2 = yield* TxRef.get(that.ref)
681 const diff = HashSet.difference(set1, set2)
682 return yield* fromHashSet(diff)
683 }).pipe(Effect.tx))
684
685/**
686 * Checks whether a TxHashSet is a subset of another TxHashSet.
687 *
688 * **Example** (Checking subset relationships)
689 *
690 * ```ts import.meta.vitest
691 * import { Effect, TxHashSet } from "effect"
692 *
693 * const program = Effect.gen(function*() {
694 * const small = yield* TxHashSet.make("a", "b")
695 * const large = yield* TxHashSet.make("a", "b", "c", "d")
696 * const other = yield* TxHashSet.make("x", "y")
697 *
698 * yield* TxHashSet.isSubset(small, large) // => true
699 * yield* TxHashSet.isSubset(large, small) // => false
700 * yield* TxHashSet.isSubset(small, other) // => false
701 * yield* TxHashSet.isSubset(small, small) // => true
702 * })
703 *
704 * await Effect.runPromise(program)
705 * ```
706 *
707 * @category predicates
708 * @since 4.0.0
709 */
710export const isSubset: {
711 <V1>(that: TxHashSet<V1>): <V0>(self: TxHashSet<V0>) => Effect.Effect<boolean>
712 <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>): Effect.Effect<boolean>
713} = dual<
714 <V1>(that: TxHashSet<V1>) => <V0>(self: TxHashSet<V0>) => Effect.Effect<boolean>,
715 <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>) => Effect.Effect<boolean>
716>(2, <V0, V1>(self: TxHashSet<V0>, that: TxHashSet<V1>) =>
717 Effect.gen(function*() {
718 const set1 = yield* TxRef.get(self.ref)
719 const set2 = yield* TxRef.get(that.ref)
720 return HashSet.isSubset(set1, set2)
721 }).pipe(Effect.tx))
722
723/**
724 * Checks whether at least one value in the TxHashSet satisfies the predicate.
725 *
726 * **Example** (Testing whether some values match)
727 *
728 * ```ts import.meta.vitest
729 * import { Effect, TxHashSet } from "effect"
730 *
731 * const program = Effect.gen(function*() {
732 * const numbers = yield* TxHashSet.make(1, 2, 3, 4, 5)
733 *
734 * yield* TxHashSet.some(numbers, (n) => n > 3) // => true
735 * yield* TxHashSet.some(numbers, (n) => n > 10) // => false
736 *
737 * const empty = yield* TxHashSet.empty<number>()
738 * yield* TxHashSet.some(empty, (n) => n > 0) // => false
739 * })
740 *
741 * await Effect.runPromise(program)
742 * ```
743 *
744 * @category predicates
745 * @since 4.0.0
746 */
747export const some: {
748 <V>(predicate: Predicate<V>): (self: TxHashSet<V>) => Effect.Effect<boolean>
749 <V>(self: TxHashSet<V>, predicate: Predicate<V>): Effect.Effect<boolean>
750} = dual<
751 <V>(predicate: Predicate<V>) => (self: TxHashSet<V>) => Effect.Effect<boolean>,
752 <V>(self: TxHashSet<V>, predicate: Predicate<V>) => Effect.Effect<boolean>
753>(2, <V>(self: TxHashSet<V>, predicate: Predicate<V>) =>
754 Effect.gen(function*() {
755 const set = yield* TxRef.get(self.ref)
756 return HashSet.some(set, predicate)
757 }))
758
759/**
760 * Checks whether all values in the TxHashSet satisfy the predicate.
761 *
762 * **Example** (Testing whether every value matches)
763 *
764 * ```ts import.meta.vitest
765 * import { Effect, TxHashSet } from "effect"
766 *
767 * const program = Effect.gen(function*() {
768 * const numbers = yield* TxHashSet.make(2, 4, 6, 8)
769 *
770 * yield* TxHashSet.every(numbers, (n) => n % 2 === 0) // => true
771 * yield* TxHashSet.every(numbers, (n) => n > 5) // => false
772 *
773 * const empty = yield* TxHashSet.empty<number>()
774 * yield* TxHashSet.every(empty, (n) => n > 0) // => true
775 * })
776 *
777 * await Effect.runPromise(program)
778 * ```
779 *
780 * @category predicates
781 * @since 4.0.0
782 */
783export const every: {
784 <V>(predicate: Predicate<V>): (self: TxHashSet<V>) => Effect.Effect<boolean>
785 <V>(self: TxHashSet<V>, predicate: Predicate<V>): Effect.Effect<boolean>
786} = dual<
787 <V>(predicate: Predicate<V>) => (self: TxHashSet<V>) => Effect.Effect<boolean>,
788 <V>(self: TxHashSet<V>, predicate: Predicate<V>) => Effect.Effect<boolean>
789>(2, <V>(self: TxHashSet<V>, predicate: Predicate<V>) =>
790 Effect.gen(function*() {
791 const set = yield* TxRef.get(self.ref)
792 return HashSet.every(set, predicate)
793 }))
794
795/**
796 * Maps each value in the TxHashSet using the provided function, returning a new TxHashSet.
797 *
798 * **Example** (Mapping values)
799 *
800 * ```ts import.meta.vitest
801 * import { Effect, TxHashSet } from "effect"
802 *
803 * const program = Effect.gen(function*() {
804 * const numbers = yield* TxHashSet.make(1, 2, 3)
805 * const doubled = yield* TxHashSet.map(numbers, (n) => n * 2)
806 *
807 * Array.from(yield* TxHashSet.toHashSet(doubled)).sort() // => [2, 4, 6]
808 * yield* TxHashSet.size(doubled) // => 3
809 *
810 * // Mapping can reduce size if function produces duplicates
811 * const strings = yield* TxHashSet.make("apple", "banana", "cherry")
812 * const lengths = yield* TxHashSet.map(strings, (s) => s.length)
813 * Array.from(yield* TxHashSet.toHashSet(lengths)).sort() // => [5, 6]
814 * })
815 *
816 * await Effect.runPromise(program)
817 * ```
818 *
819 * @category mapping
820 * @since 4.0.0
821 */
822export const map: {
823 <V, U>(f: (value: V) => U): (self: TxHashSet<V>) => Effect.Effect<TxHashSet<U>>
824 <V, U>(self: TxHashSet<V>, f: (value: V) => U): Effect.Effect<TxHashSet<U>>
825} = dual<
826 <V, U>(f: (value: V) => U) => (self: TxHashSet<V>) => Effect.Effect<TxHashSet<U>>,
827 <V, U>(self: TxHashSet<V>, f: (value: V) => U) => Effect.Effect<TxHashSet<U>>
828>(2, <V, U>(self: TxHashSet<V>, f: (value: V) => U) =>
829 Effect.gen(function*() {
830 const currentSet = yield* TxRef.get(self.ref)
831 const mappedSet = HashSet.map(currentSet, f)
832 return yield* fromHashSet(mappedSet)
833 }).pipe(Effect.tx))
834
835/**
836 * Filters the TxHashSet keeping only values that satisfy the predicate, returning a new TxHashSet.
837 *
838 * **Example** (Filtering values)
839 *
840 * ```ts import.meta.vitest
841 * import { Effect, TxHashSet } from "effect"
842 *
843 * const program = Effect.gen(function*() {
844 * const numbers = yield* TxHashSet.make(1, 2, 3, 4, 5, 6)
845 * const evens = yield* TxHashSet.filter(numbers, (n) => n % 2 === 0)
846 *
847 * Array.from(yield* TxHashSet.toHashSet(evens)).sort() // => [2, 4, 6]
848 * yield* TxHashSet.size(evens) // => 3
849 * })
850 *
851 * await Effect.runPromise(program)
852 * ```
853 *
854 * @category filtering
855 * @since 4.0.0
856 */
857export const filter: {
858 <V, U extends V>(
859 refinement: Refinement<NoInfer<V>, U>
860 ): (self: TxHashSet<V>) => Effect.Effect<TxHashSet<U>>
861 <V>(
862 predicate: Predicate<NoInfer<V>>
863 ): (self: TxHashSet<V>) => Effect.Effect<TxHashSet<V>>
864 <V, U extends V>(
865 self: TxHashSet<V>,
866 refinement: Refinement<V, U>
867 ): Effect.Effect<TxHashSet<U>>
868 <V>(self: TxHashSet<V>, predicate: Predicate<V>): Effect.Effect<TxHashSet<V>>
869} = dual<
870 {
871 <V, U extends V>(
872 refinement: Refinement<NoInfer<V>, U>
873 ): (self: TxHashSet<V>) => Effect.Effect<TxHashSet<U>>
874 <V>(
875 predicate: Predicate<NoInfer<V>>
876 ): (self: TxHashSet<V>) => Effect.Effect<TxHashSet<V>>
877 },
878 {
879 <V, U extends V>(
880 self: TxHashSet<V>,
881 refinement: Refinement<V, U>
882 ): Effect.Effect<TxHashSet<U>>
883 <V>(self: TxHashSet<V>, predicate: Predicate<V>): Effect.Effect<TxHashSet<V>>
884 }
885>(2, <V>(self: TxHashSet<V>, predicate: Predicate<V>) =>
886 Effect.gen(function*() {
887 const currentSet = yield* TxRef.get(self.ref)
888 const filteredSet = HashSet.filter(currentSet, predicate)
889 return yield* fromHashSet(filteredSet)
890 }).pipe(Effect.tx))
891
892/**
893 * Reduces the TxHashSet to a single value by iterating through the values and applying an accumulator function.
894 *
895 * **Example** (Reducing values)
896 *
897 * ```ts import.meta.vitest
898 * import { Effect, TxHashSet } from "effect"
899 *
900 * const program = Effect.gen(function*() {
901 * const numbers = yield* TxHashSet.make(1, 2, 3, 4, 5)
902 * yield* TxHashSet.reduce(numbers, 0, (acc, n) => acc + n) // => 15
903 *
904 * const strings = yield* TxHashSet.make("a", "b", "c")
905 * String(yield* TxHashSet.reduce(strings, "", (acc, s) => acc + s)).split("").sort().join("") // => "abc"
906 * })
907 *
908 * await Effect.runPromise(program)
909 * ```
910 *
911 * @category folding
912 * @since 2.0.0
913 */
914export const reduce: {
915 <V, U>(
916 zero: U,
917 f: (accumulator: U, value: V) => U
918 ): (self: TxHashSet<V>) => Effect.Effect<U>
919 <V, U>(
920 self: TxHashSet<V>,
921 zero: U,
922 f: (accumulator: U, value: V) => U
923 ): Effect.Effect<U>
924} = dual<
925 <V, U>(
926 zero: U,
927 f: (accumulator: U, value: V) => U
928 ) => (self: TxHashSet<V>) => Effect.Effect<U>,
929 <V, U>(
930 self: TxHashSet<V>,
931 zero: U,
932 f: (accumulator: U, value: V) => U
933 ) => Effect.Effect<U>
934>(3, <V, U>(self: TxHashSet<V>, zero: U, f: (accumulator: U, value: V) => U) =>
935 Effect.gen(function*() {
936 const set = yield* TxRef.get(self.ref)
937 return HashSet.reduce(set, zero, f)
938 }))
939
940/**
941 * Converts the TxHashSet to an immutable HashSet snapshot.
942 *
943 * **Example** (Taking a HashSet snapshot)
944 *
945 * ```ts import.meta.vitest
946 * import { Effect, HashSet, TxHashSet } from "effect"
947 *
948 * const program = Effect.gen(function*() {
949 * const txSet = yield* TxHashSet.make("x", "y", "z")
950 * const hashSet = yield* TxHashSet.toHashSet(txSet)
951 *
952 * HashSet.size(hashSet) // => 3
953 * HashSet.has(hashSet, "y") // => true
954 *
955 * // hashSet is a snapshot - modifications to txSet don't affect it
956 * yield* TxHashSet.add(txSet, "w")
957 * HashSet.size(hashSet) // => 3
958 * yield* TxHashSet.size(txSet) // => 4
959 * })
960 *
961 * await Effect.runPromise(program)
962 * ```
963 *
964 * @category converting
965 * @since 2.0.0
966 */
967export const toHashSet = <V>(self: TxHashSet<V>): Effect.Effect<HashSet.HashSet<V>> => TxRef.get(self.ref)