1/**
2 * Stores a `Chunk` inside transactional state.
3 *
4 * A `TxChunk<A>` keeps its current `Chunk<A>` in a `TxRef`, so reads and
5 * updates can be committed atomically with other transactional operations. This
6 * module offers a transactional version of common chunk workflows, including
7 * creating collections, reading or replacing the current chunk, adding or
8 * removing values, checking size, slicing, mapping, filtering, and combining
9 * chunks.
10 *
11 * @since 4.0.0
12 */
13import * as Chunk from "./Chunk.ts"
14import * as Effect from "./Effect.ts"
15import { format } from "./Formatter.ts"
16import { dual } from "./Function.ts"
17import type { Inspectable } from "./Inspectable.ts"
18import { NodeInspectSymbol, toJson } from "./Inspectable.ts"
19import type { Pipeable } from "./Pipeable.ts"
20import { pipeArguments } from "./Pipeable.ts"
21import { hasProperty } from "./Predicate.ts"
22import * as TxRef from "./TxRef.ts"
23import type { NoInfer } from "./Types.ts"
24
25const TypeId = "~effect/TxChunk"
26
27/**
28 * TxChunk is a transactional chunk data structure that provides Software Transactional Memory (STM)
29 * semantics for chunk operations.
30 *
31 * **Details**
32 *
33 * Accessed values are tracked by the transaction in order to detect conflicts and to track changes.
34 * A transaction will retry whenever a conflict is detected or whenever the transaction explicitly
35 * calls `Effect.txRetry` and any of the accessed TxChunk values change.
36 *
37 * **Example** (Using a transactional chunk)
38 *
39 * ```ts import.meta.vitest
40 * import { Chunk, Effect, TxChunk } from "effect"
41 *
42 * const program = Effect.gen(function*() {
43 * // Create a transactional chunk
44 * const txChunk: TxChunk.TxChunk<number> = yield* TxChunk.fromIterable([
45 * 1,
46 * 2,
47 * 3
48 * ])
49 *
50 * // Single operations - no explicit transaction needed
51 * yield* TxChunk.append(txChunk, 4)
52 * const result = yield* TxChunk.get(txChunk)
53 *
54 * // Multi-step atomic operation - use explicit transaction
55 * yield* Effect.tx(
56 * Effect.gen(function*() {
57 * yield* TxChunk.prepend(txChunk, 0)
58 * yield* TxChunk.append(txChunk, 5)
59 * })
60 * )
61 *
62 * const finalResult = yield* TxChunk.get(txChunk)
63 * return [Chunk.toArray(result), Chunk.toArray(finalResult)]
64 * })
65 *
66 * await Effect.runPromise(program) // => [[1, 2, 3, 4], [0, 1, 2, 3, 4, 5]]
67 * ```
68 *
69 * @category models
70 * @since 4.0.0
71 */
72export interface TxChunk<in out A> extends Inspectable, Pipeable {
73 readonly [TypeId]: typeof TypeId
74 readonly ref: TxRef.TxRef<Chunk.Chunk<A>>
75}
76
77const TxChunkProto = {
78 [NodeInspectSymbol](this: TxChunk<unknown>) {
79 return this.toJSON()
80 },
81 toString(this: TxChunk<unknown>) {
82 return `TxChunk(${format(toJson((this).ref))})`
83 },
84 toJSON(this: TxChunk<unknown>) {
85 return {
86 _id: "TxChunk",
87 ref: toJson((this).ref)
88 }
89 },
90 pipe(this: TxChunk<unknown>) {
91 return pipeArguments(this, arguments)
92 }
93}
94
95/**
96 * Creates a new `TxChunk` with the specified initial chunk.
97 *
98 * **Details**
99 *
100 * This function returns a new TxChunk reference containing the provided initial chunk. No existing
101 * TxChunk instances are modified.
102 *
103 * **Example** (Creating a TxChunk from a chunk)
104 *
105 * ```ts import.meta.vitest
106 * import { Chunk, Effect, TxChunk } from "effect"
107 *
108 * const program = Effect.gen(function*() {
109 * // Create a TxChunk with initial values
110 * const initialChunk = Chunk.fromIterable([1, 2, 3])
111 * const txChunk = yield* TxChunk.make(initialChunk)
112 *
113 * // Read the value - automatically transactional
114 * const result = yield* TxChunk.get(txChunk)
115 * return Chunk.toArray(result)
116 * })
117 *
118 * await Effect.runPromise(program) // => [1, 2, 3]
119 * ```
120 *
121 * @category constructors
122 * @since 4.0.0
123 */
124export const make = <A>(initial: Chunk.Chunk<A>): Effect.Effect<TxChunk<A>> =>
125 Effect.map(TxRef.make(initial), (ref) => makeUnsafe(ref))
126
127/**
128 * Creates a new empty `TxChunk`.
129 *
130 * **Details**
131 *
132 * This function returns a new TxChunk reference that is initially empty. No existing TxChunk
133 * instances are modified.
134 *
135 * **Example** (Creating an empty TxChunk)
136 *
137 * ```ts import.meta.vitest
138 * import { Effect, TxChunk } from "effect"
139 *
140 * const program = Effect.gen(function*() {
141 * // Create an empty TxChunk
142 * const txChunk = yield* TxChunk.empty<number>()
143 *
144 * // Check if it's empty - automatically transactional
145 * const isEmpty = yield* TxChunk.isEmpty(txChunk)
146 *
147 * // Add elements - automatically transactional
148 * yield* TxChunk.append(txChunk, 42)
149 *
150 * const isStillEmpty = yield* TxChunk.isEmpty(txChunk)
151 * return [isEmpty, isStillEmpty]
152 * })
153 *
154 * await Effect.runPromise(program) // => [true, false]
155 * ```
156 *
157 * @category constructors
158 * @since 4.0.0
159 */
160export const empty = <A = never>(): Effect.Effect<TxChunk<A>> =>
161 Effect.map(TxRef.make(Chunk.empty<A>()), (ref) => makeUnsafe(ref))
162
163/**
164 * Creates a new `TxChunk` from an iterable.
165 *
166 * **Details**
167 *
168 * This function returns a new TxChunk reference containing elements from the provided iterable. No
169 * existing TxChunk instances are modified.
170 *
171 * **Example** (Creating from an iterable)
172 *
173 * ```ts import.meta.vitest
174 * import { Chunk, Effect, TxChunk } from "effect"
175 *
176 * const program = Effect.gen(function*() {
177 * // Create TxChunk from array
178 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
179 *
180 * // Read the contents - automatically transactional
181 * const chunk = yield* TxChunk.get(txChunk)
182 *
183 * // Multi-step atomic modification - use explicit transaction
184 * yield* Effect.tx(
185 * Effect.gen(function*() {
186 * yield* TxChunk.append(txChunk, 6)
187 * yield* TxChunk.prepend(txChunk, 0)
188 * })
189 * )
190 *
191 * const updated = yield* TxChunk.get(txChunk)
192 * return [Chunk.toArray(chunk), Chunk.toArray(updated)]
193 * })
194 *
195 * await Effect.runPromise(program) // => [[1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6]]
196 * ```
197 *
198 * @category constructors
199 * @since 4.0.0
200 */
201export const fromIterable = <A>(iterable: Iterable<A>): Effect.Effect<TxChunk<A>> =>
202 Effect.map(TxRef.make(Chunk.fromIterable(iterable)), (ref) => makeUnsafe(ref))
203
204/**
205 * Creates a new `TxChunk` with the specified TxRef.
206 *
207 * **Details**
208 *
209 * This function returns a new TxChunk reference wrapping the provided TxRef. No existing TxChunk
210 * instances are modified.
211 *
212 * **Example** (Wrapping an existing TxRef)
213 *
214 * ```ts import.meta.vitest
215 * import { Chunk, Effect, TxChunk, TxRef } from "effect"
216 *
217 * // Create a TxChunk from an existing TxRef (advanced usage)
218 * const ref = TxRef.makeUnsafe(Chunk.fromIterable([1, 2, 3]))
219 * const txChunk = TxChunk.makeUnsafe(ref)
220 * Chunk.toArray(await Effect.runPromise(TxChunk.get(txChunk))) // => [1, 2, 3]
221 * ```
222 *
223 * @category constructors
224 * @since 4.0.0
225 */
226export const makeUnsafe = <A>(ref: TxRef.TxRef<Chunk.Chunk<A>>): TxChunk<A> => {
227 const txChunk = Object.create(TxChunkProto)
228 txChunk[TypeId] = TypeId
229 txChunk.ref = ref
230 return txChunk
231}
232
233/**
234 * Checks whether `u` is a `TxChunk<unknown>`.
235 *
236 * **Example** (Checking for transactional chunks)
237 *
238 * ```ts import.meta.vitest
239 * import { Chunk, TxChunk, TxRef } from "effect"
240 *
241 * const txChunk = TxChunk.makeUnsafe(TxRef.makeUnsafe(Chunk.empty<number>()))
242 *
243 * TxChunk.isTxChunk(txChunk) // => true
244 * TxChunk.isTxChunk(Chunk.empty()) // => false
245 * ```
246 *
247 * @category guards
248 * @since 4.0.0
249 */
250export const isTxChunk = (u: unknown): u is TxChunk<unknown> => hasProperty(u, TypeId)
251
252/**
253 * Modifies the value of the `TxChunk` using the provided function.
254 *
255 * **Details**
256 *
257 * This function mutates the original TxChunk by updating its internal state. It does not return a
258 * new TxChunk reference.
259 *
260 * **Example** (Modifying while returning a value)
261 *
262 * ```ts import.meta.vitest
263 * import { Chunk, Effect, TxChunk } from "effect"
264 *
265 * const program = Effect.gen(function*() {
266 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
267 *
268 * // Modify and return both old size and new chunk
269 * const oldSize = yield* TxChunk.modify(txChunk, (chunk) => [
270 * Chunk.size(chunk), // return value (old size)
271 * Chunk.append(chunk, 4) // new value
272 * ])
273 *
274 * const newChunk = yield* TxChunk.get(txChunk)
275 * return [oldSize, Chunk.toArray(newChunk)]
276 * })
277 *
278 * await Effect.runPromise(program) // => [3, [1, 2, 3, 4]]
279 * ```
280 *
281 * @category combinators
282 * @since 4.0.0
283 */
284export const modify: {
285 <A, R>(
286 f: (current: Chunk.Chunk<NoInfer<A>>) => [returnValue: R, newValue: Chunk.Chunk<A>]
287 ): (self: TxChunk<A>) => Effect.Effect<R>
288 <A, R>(
289 self: TxChunk<A>,
290 f: (current: Chunk.Chunk<A>) => [returnValue: R, newValue: Chunk.Chunk<A>]
291 ): Effect.Effect<R>
292} = dual(
293 2,
294 <A, R>(
295 self: TxChunk<A>,
296 f: (current: Chunk.Chunk<A>) => [returnValue: R, newValue: Chunk.Chunk<A>]
297 ): Effect.Effect<R> => TxRef.modify(self.ref, f)
298)
299
300/**
301 * Updates the value of the `TxChunk` using the provided function.
302 *
303 * **Details**
304 *
305 * This function mutates the original TxChunk by updating its internal state. It does not return a
306 * new TxChunk reference.
307 *
308 * **Example** (Updating the stored chunk)
309 *
310 * ```ts import.meta.vitest
311 * import { Chunk, Effect, TxChunk } from "effect"
312 *
313 * const program = Effect.gen(function*() {
314 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
315 *
316 * // Update the chunk by reversing it atomically
317 * yield* TxChunk.update(txChunk, (chunk) => Chunk.reverse(chunk))
318 *
319 * const result = yield* TxChunk.get(txChunk)
320 * return Chunk.toArray(result)
321 * })
322 *
323 * await Effect.runPromise(program) // => [3, 2, 1]
324 * ```
325 *
326 * @category combinators
327 * @since 4.0.0
328 */
329export const update: {
330 <A>(f: (current: Chunk.Chunk<NoInfer<A>>) => Chunk.Chunk<A>): (self: TxChunk<A>) => Effect.Effect<void>
331 <A>(self: TxChunk<A>, f: (current: Chunk.Chunk<A>) => Chunk.Chunk<A>): Effect.Effect<void>
332} = dual(
333 2,
334 <A>(
335 self: TxChunk<A>,
336 f: (current: Chunk.Chunk<A>) => Chunk.Chunk<A>
337 ): Effect.Effect<void> => TxRef.update(self.ref, f)
338)
339
340/**
341 * Reads the current chunk from the `TxChunk`.
342 *
343 * **Example** (Reading the current chunk)
344 *
345 * ```ts import.meta.vitest
346 * import { Chunk, Effect, TxChunk } from "effect"
347 *
348 * const program = Effect.gen(function*() {
349 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
350 *
351 * // Read the current value within a transaction
352 * const chunk = yield* TxChunk.get(txChunk)
353 * return [Chunk.toArray(chunk), Chunk.size(chunk)]
354 * })
355 *
356 * await Effect.runPromise(program) // => [[1, 2, 3], 3]
357 * ```
358 *
359 * @category combinators
360 * @since 4.0.0
361 */
362export const get = <A>(self: TxChunk<A>): Effect.Effect<Chunk.Chunk<A>> => TxRef.get(self.ref)
363
364/**
365 * Sets the value of the `TxChunk`.
366 *
367 * **Details**
368 *
369 * This function mutates the original TxChunk by replacing its internal state with the provided
370 * chunk. It does not return a new TxChunk reference.
371 *
372 * **Example** (Replacing the stored chunk)
373 *
374 * ```ts import.meta.vitest
375 * import { Chunk, Effect, TxChunk } from "effect"
376 *
377 * const program = Effect.gen(function*() {
378 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
379 *
380 * // Replace the entire chunk content
381 * const newChunk = Chunk.fromIterable([10, 20, 30, 40])
382 * yield* TxChunk.set(txChunk, newChunk)
383 *
384 * const result = yield* TxChunk.get(txChunk)
385 * return Chunk.toArray(result)
386 * })
387 *
388 * await Effect.runPromise(program) // => [10, 20, 30, 40]
389 * ```
390 *
391 * @category combinators
392 * @since 4.0.0
393 */
394export const set: {
395 <A>(chunk: Chunk.Chunk<A>): (self: TxChunk<A>) => Effect.Effect<void>
396 <A>(self: TxChunk<A>, chunk: Chunk.Chunk<A>): Effect.Effect<void>
397} = dual(
398 2,
399 <A>(self: TxChunk<A>, chunk: Chunk.Chunk<A>): Effect.Effect<void> => TxRef.set(self.ref, chunk)
400)
401
402/**
403 * Appends an element to the end of the `TxChunk`.
404 *
405 * **Details**
406 *
407 * This function mutates the original TxChunk by adding the element to the end. It does not return a
408 * new TxChunk reference.
409 *
410 * **Example** (Appending an element)
411 *
412 * ```ts import.meta.vitest
413 * import { Chunk, Effect, TxChunk } from "effect"
414 *
415 * const program = Effect.gen(function*() {
416 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
417 *
418 * // Add element to the end atomically
419 * yield* TxChunk.append(txChunk, 4)
420 *
421 * const result = yield* TxChunk.get(txChunk)
422 * return Chunk.toArray(result)
423 * })
424 *
425 * await Effect.runPromise(program) // => [1, 2, 3, 4]
426 * ```
427 *
428 * @category combinators
429 * @since 4.0.0
430 */
431export const append: {
432 <A>(element: A): (self: TxChunk<A>) => Effect.Effect<void>
433 <A>(self: TxChunk<A>, element: A): Effect.Effect<void>
434} = dual(
435 2,
436 <A>(self: TxChunk<A>, element: A): Effect.Effect<void> => update(self, (current) => Chunk.append(current, element))
437)
438
439/**
440 * Prepends an element to the beginning of the `TxChunk`.
441 *
442 * **Details**
443 *
444 * This function mutates the original TxChunk by adding the element to the beginning. It does not
445 * return a new TxChunk reference.
446 *
447 * **Example** (Prepending an element)
448 *
449 * ```ts import.meta.vitest
450 * import { Chunk, Effect, TxChunk } from "effect"
451 *
452 * const program = Effect.gen(function*() {
453 * const txChunk = yield* TxChunk.fromIterable([2, 3, 4])
454 *
455 * // Add element to the beginning atomically
456 * yield* TxChunk.prepend(txChunk, 1)
457 *
458 * const result = yield* TxChunk.get(txChunk)
459 * return Chunk.toArray(result)
460 * })
461 *
462 * await Effect.runPromise(program) // => [1, 2, 3, 4]
463 * ```
464 *
465 * @category combinators
466 * @since 4.0.0
467 */
468export const prepend: {
469 <A>(element: A): (self: TxChunk<A>) => Effect.Effect<void>
470 <A>(self: TxChunk<A>, element: A): Effect.Effect<void>
471} = dual(
472 2,
473 <A>(self: TxChunk<A>, element: A): Effect.Effect<void> => update(self, (current) => Chunk.prepend(current, element))
474)
475
476/**
477 * Gets the size of the `TxChunk`.
478 *
479 * **Example** (Getting the size)
480 *
481 * ```ts import.meta.vitest
482 * import { Effect, TxChunk } from "effect"
483 *
484 * const program = Effect.gen(function*() {
485 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
486 *
487 * // Get the current size - automatically transactional
488 * const currentSize = yield* TxChunk.size(txChunk)
489 *
490 * // Size is tracked for conflict detection
491 * yield* TxChunk.append(txChunk, 6)
492 * const newSize = yield* TxChunk.size(txChunk)
493 * return [currentSize, newSize]
494 * })
495 *
496 * await Effect.runPromise(program) // => [5, 6]
497 * ```
498 *
499 * @category combinators
500 * @since 4.0.0
501 */
502export const size = <A>(self: TxChunk<A>): Effect.Effect<number> =>
503 modify(self, (current) => [Chunk.size(current), current])
504
505/**
506 * Checks whether the `TxChunk` is empty.
507 *
508 * **Example** (Checking for an empty chunk)
509 *
510 * ```ts import.meta.vitest
511 * import { Effect, TxChunk } from "effect"
512 *
513 * const program = Effect.gen(function*() {
514 * const emptyChunk = yield* TxChunk.empty<number>()
515 * const nonEmptyChunk = yield* TxChunk.fromIterable([1, 2, 3])
516 *
517 * // Check if chunks are empty - automatically transactional
518 * const isEmpty1 = yield* TxChunk.isEmpty(emptyChunk)
519 * const isEmpty2 = yield* TxChunk.isEmpty(nonEmptyChunk)
520 *
521 * return [isEmpty1, isEmpty2]
522 * })
523 *
524 * await Effect.runPromise(program) // => [true, false]
525 * ```
526 *
527 * @category predicates
528 * @since 4.0.0
529 */
530export const isEmpty = <A>(self: TxChunk<A>): Effect.Effect<boolean> =>
531 modify(self, (current) => [Chunk.isEmpty(current), current])
532
533/**
534 * Checks whether the `TxChunk` is non-empty.
535 *
536 * **Example** (Checking for a non-empty chunk)
537 *
538 * ```ts import.meta.vitest
539 * import { Effect, TxChunk } from "effect"
540 *
541 * const program = Effect.gen(function*() {
542 * const emptyChunk = yield* TxChunk.empty<number>()
543 * const nonEmptyChunk = yield* TxChunk.fromIterable([1, 2, 3])
544 *
545 * // Check if chunks are non-empty - automatically transactional
546 * const isNonEmpty1 = yield* TxChunk.isNonEmpty(emptyChunk)
547 * const isNonEmpty2 = yield* TxChunk.isNonEmpty(nonEmptyChunk)
548 *
549 * return [isNonEmpty1, isNonEmpty2]
550 * })
551 *
552 * await Effect.runPromise(program) // => [false, true]
553 * ```
554 *
555 * @category predicates
556 * @since 4.0.0
557 */
558export const isNonEmpty = <A>(self: TxChunk<A>): Effect.Effect<boolean> =>
559 modify(self, (current) => [Chunk.isNonEmpty(current), current])
560
561/**
562 * Takes the first `n` elements from the `TxChunk`.
563 *
564 * **Details**
565 *
566 * This function mutates the original TxChunk by keeping only the first n elements. It does not
567 * return a new TxChunk reference.
568 *
569 * **Example** (Taking leading elements)
570 *
571 * ```ts import.meta.vitest
572 * import { Chunk, Effect, TxChunk } from "effect"
573 *
574 * const program = Effect.gen(function*() {
575 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
576 *
577 * // Take only the first 3 elements - automatically transactional
578 * yield* TxChunk.take(txChunk, 3)
579 *
580 * const result = yield* TxChunk.get(txChunk)
581 * return Chunk.toArray(result)
582 * })
583 *
584 * await Effect.runPromise(program) // => [1, 2, 3]
585 * ```
586 *
587 * @category combinators
588 * @since 4.0.0
589 */
590export const take: {
591 (n: number): <A>(self: TxChunk<A>) => Effect.Effect<void>
592 <A>(self: TxChunk<A>, n: number): Effect.Effect<void>
593} = dual(
594 2,
595 <A>(self: TxChunk<A>, n: number): Effect.Effect<void> => update(self, (current) => Chunk.take(current, n))
596)
597
598/**
599 * Drops the first `n` elements from the `TxChunk`.
600 *
601 * **Details**
602 *
603 * This function mutates the original TxChunk by removing the first n elements. It does not return a
604 * new TxChunk reference.
605 *
606 * **Example** (Dropping leading elements)
607 *
608 * ```ts import.meta.vitest
609 * import { Chunk, Effect, TxChunk } from "effect"
610 *
611 * const program = Effect.gen(function*() {
612 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5])
613 *
614 * // Drop the first 2 elements - automatically transactional
615 * yield* TxChunk.drop(txChunk, 2)
616 *
617 * const result = yield* TxChunk.get(txChunk)
618 * return Chunk.toArray(result)
619 * })
620 *
621 * await Effect.runPromise(program) // => [3, 4, 5]
622 * ```
623 *
624 * @category combinators
625 * @since 4.0.0
626 */
627export const drop: {
628 (n: number): <A>(self: TxChunk<A>) => Effect.Effect<void>
629 <A>(self: TxChunk<A>, n: number): Effect.Effect<void>
630} = dual(
631 2,
632 <A>(self: TxChunk<A>, n: number): Effect.Effect<void> => update(self, (current) => Chunk.drop(current, n))
633)
634
635/**
636 * Takes a slice of the `TxChunk` from `start` to `end` (exclusive).
637 *
638 * **Details**
639 *
640 * This function mutates the original TxChunk by keeping only the elements in the specified range. It
641 * does not return a new TxChunk reference.
642 *
643 * **Example** (Taking a slice)
644 *
645 * ```ts import.meta.vitest
646 * import { Chunk, Effect, TxChunk } from "effect"
647 *
648 * const program = Effect.gen(function*() {
649 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5, 6, 7])
650 *
651 * // Take elements from index 2 to 5 (exclusive) - automatically transactional
652 * yield* TxChunk.slice(txChunk, 2, 5)
653 *
654 * const result = yield* TxChunk.get(txChunk)
655 * return Chunk.toArray(result)
656 * })
657 *
658 * await Effect.runPromise(program) // => [3, 4, 5]
659 * ```
660 *
661 * @category combinators
662 * @since 4.0.0
663 */
664export const slice: {
665 (start: number, end: number): <A>(self: TxChunk<A>) => Effect.Effect<void>
666 <A>(self: TxChunk<A>, start: number, end: number): Effect.Effect<void>
667} = dual(
668 3,
669 <A>(self: TxChunk<A>, start: number, end: number): Effect.Effect<void> =>
670 update(self, (current) => Chunk.take(Chunk.drop(current, start), end - start))
671)
672
673/**
674 * Maps each element of the `TxChunk` using a function that returns the same
675 * element type.
676 *
677 * **Details**
678 *
679 * This function mutates the original `TxChunk` by transforming each element in place. It does not
680 * return a new `TxChunk` reference.
681 *
682 * **Example** (Mapping elements)
683 *
684 * ```ts import.meta.vitest
685 * import { Chunk, Effect, TxChunk } from "effect"
686 *
687 * const program = Effect.gen(function*() {
688 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4])
689 *
690 * // Transform each element atomically (must maintain same type)
691 * yield* TxChunk.map(txChunk, (n) => n * 2)
692 *
693 * const result = yield* TxChunk.get(txChunk)
694 * return Chunk.toArray(result)
695 * })
696 *
697 * await Effect.runPromise(program) // => [2, 4, 6, 8]
698 * ```
699 *
700 * @category combinators
701 * @since 4.0.0
702 */
703export const map: {
704 <A>(f: (a: NoInfer<A>) => A): (self: TxChunk<A>) => Effect.Effect<void>
705 <A>(self: TxChunk<A>, f: (a: A) => A): Effect.Effect<void>
706} = dual(
707 2,
708 <A>(self: TxChunk<A>, f: (a: A) => A): Effect.Effect<void> => update(self, (current) => Chunk.map(current, f))
709)
710
711/**
712 * Filters the `TxChunk` keeping only elements that satisfy the predicate.
713 *
714 * **Details**
715 *
716 * This function mutates the original TxChunk by removing elements that don't match the predicate. It
717 * does not return a new TxChunk reference.
718 *
719 * **Example** (Filtering elements)
720 *
721 * ```ts import.meta.vitest
722 * import { Chunk, Effect, TxChunk } from "effect"
723 *
724 * const program = Effect.gen(function*() {
725 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3, 4, 5, 6])
726 *
727 * // Keep only even numbers atomically
728 * yield* TxChunk.filter(txChunk, (n) => n % 2 === 0)
729 *
730 * const result = yield* TxChunk.get(txChunk)
731 * return Chunk.toArray(result)
732 * })
733 *
734 * await Effect.runPromise(program) // => [2, 4, 6]
735 * ```
736 *
737 * @category combinators
738 * @since 4.0.0
739 */
740export const filter: {
741 <A, B extends A>(refinement: (a: A) => a is B): (self: TxChunk<A>) => Effect.Effect<void>
742 <A>(predicate: (a: A) => boolean): (self: TxChunk<A>) => Effect.Effect<void>
743 <A, B extends A>(self: TxChunk<A>, refinement: (a: A) => a is B): Effect.Effect<void>
744 <A>(self: TxChunk<A>, predicate: (a: A) => boolean): Effect.Effect<void>
745} = dual(
746 2,
747 <A>(self: TxChunk<A>, predicate: (a: A) => boolean): Effect.Effect<void> =>
748 update(self, (current) => Chunk.filter(current, predicate))
749)
750
751/**
752 * Concatenates another chunk to the end of the `TxChunk`.
753 *
754 * **Details**
755 *
756 * This function mutates the original TxChunk by appending all elements from the other chunk. It does
757 * not return a new TxChunk reference.
758 *
759 * **Example** (Appending another chunk)
760 *
761 * ```ts import.meta.vitest
762 * import { Chunk, Effect, TxChunk } from "effect"
763 *
764 * const program = Effect.gen(function*() {
765 * const txChunk = yield* TxChunk.fromIterable([1, 2, 3])
766 * const otherChunk = Chunk.fromIterable([4, 5, 6])
767 *
768 * // Append all elements from another chunk atomically
769 * yield* TxChunk.appendAll(txChunk, otherChunk)
770 *
771 * const result = yield* TxChunk.get(txChunk)
772 * return Chunk.toArray(result)
773 * })
774 *
775 * await Effect.runPromise(program) // => [1, 2, 3, 4, 5, 6]
776 * ```
777 *
778 * @category combinators
779 * @since 4.0.0
780 */
781export const appendAll: {
782 <A>(other: Chunk.Chunk<A>): (self: TxChunk<A>) => Effect.Effect<void>
783 <A>(self: TxChunk<A>, other: Chunk.Chunk<A>): Effect.Effect<void>
784} = dual(
785 2,
786 <A>(self: TxChunk<A>, other: Chunk.Chunk<A>): Effect.Effect<void> =>
787 update(self, (current) => Chunk.appendAll(current, other))
788)
789
790/**
791 * Concatenates another chunk to the beginning of the `TxChunk`.
792 *
793 * **Details**
794 *
795 * This function mutates the original TxChunk by prepending all elements from the other chunk. It
796 * does not return a new TxChunk reference.
797 *
798 * **Example** (Prepending another chunk)
799 *
800 * ```ts import.meta.vitest
801 * import { Chunk, Effect, TxChunk } from "effect"
802 *
803 * const program = Effect.gen(function*() {
804 * const txChunk = yield* TxChunk.fromIterable([4, 5, 6])
805 * const otherChunk = Chunk.fromIterable([1, 2, 3])
806 *
807 * // Prepend all elements from another chunk atomically
808 * yield* TxChunk.prependAll(txChunk, otherChunk)
809 *
810 * const result = yield* TxChunk.get(txChunk)
811 * return Chunk.toArray(result)
812 * })
813 *
814 * await Effect.runPromise(program) // => [1, 2, 3, 4, 5, 6]
815 * ```
816 *
817 * @category combinators
818 * @since 4.0.0
819 */
820export const prependAll: {
821 <A>(other: Chunk.Chunk<A>): (self: TxChunk<A>) => Effect.Effect<void>
822 <A>(self: TxChunk<A>, other: Chunk.Chunk<A>): Effect.Effect<void>
823} = dual(
824 2,
825 <A>(self: TxChunk<A>, other: Chunk.Chunk<A>): Effect.Effect<void> =>
826 update(self, (current) => Chunk.prependAll(current, other))
827)
828
829/**
830 * Concatenates another `TxChunk` to the end of this `TxChunk`.
831 *
832 * **Details**
833 *
834 * This function mutates the original TxChunk by appending all elements from the other TxChunk. It
835 * does not return a new TxChunk reference.
836 *
837 * **Example** (Concatenating TxChunks)
838 *
839 * ```ts import.meta.vitest
840 * import { Chunk, Effect, TxChunk } from "effect"
841 *
842 * const program = Effect.gen(function*() {
843 * const txChunk1 = yield* TxChunk.fromIterable([1, 2, 3])
844 * const txChunk2 = yield* TxChunk.fromIterable([4, 5, 6])
845 *
846 * // Concatenate atomically within a transaction
847 * yield* TxChunk.concat(txChunk1, txChunk2)
848 *
849 * const result = yield* TxChunk.get(txChunk1)
850 *
851 * // Original txChunk2 is unchanged
852 * const original = yield* TxChunk.get(txChunk2)
853 * return [Chunk.toArray(result), Chunk.toArray(original)]
854 * })
855 *
856 * await Effect.runPromise(program) // => [[1, 2, 3, 4, 5, 6], [4, 5, 6]]
857 * ```
858 *
859 * @category combinators
860 * @since 4.0.0
861 */
862export const concat: {
863 <A>(other: TxChunk<A>): (self: TxChunk<A>) => Effect.Effect<void>
864 <A>(self: TxChunk<A>, other: TxChunk<A>): Effect.Effect<void>
865} = dual(
866 2,
867 <A>(self: TxChunk<A>, other: TxChunk<A>): Effect.Effect<void> =>
868 Effect.gen(function*() {
869 const otherChunk = yield* get(other)
870 yield* appendAll(self, otherChunk)
871 }).pipe(Effect.tx)
872)