1/**
2 * Stores synchronous mutable state in a small reference object.
3 *
4 * A `MutableRef<A>` stores one current value and exposes it through `.current`.
5 * Unlike `Ref`, its operations are synchronous and update the same object in
6 * place. This module includes pipeable helpers for reading, setting, comparing,
7 * and updating the value, plus numeric increment/decrement helpers and a
8 * boolean toggle helper.
9 *
10 * @since 2.0.0
11 */
12import * as Equal from "./Equal.ts"
13import * as Dual from "./Function.ts"
14import { type Inspectable, toJson } from "./Inspectable.ts"
15import { PipeInspectableProto } from "./internal/core.ts"
16import type { Pipeable } from "./Pipeable.ts"
17
18const TypeId = "~effect/MutableRef"
19
20/**
21 * A synchronous mutable reference that stores a current value.
22 *
23 * **When to use**
24 *
25 * Use to keep local mutable state in a stable, pipeable reference.
26 *
27 * **Details**
28 *
29 * Read or write the value directly through `.current`, or use the `MutableRef`
30 * helpers for pipeable updates such as `get`, `set`, `update`, and
31 * `compareAndSet`. All operations mutate the same reference in place.
32 *
33 * **Example** (Creating and updating refs)
34 *
35 * ```ts import.meta.vitest
36 * import { MutableRef } from "effect"
37 *
38 * // Create a mutable reference
39 * const ref: MutableRef.MutableRef<number> = MutableRef.make(42)
40 *
41 * // Read the current value
42 * ref.current // => 42
43 * MutableRef.get(ref) // => 42
44 *
45 * // Update the value
46 * ref.current = 100
47 *
48 * MutableRef.get(ref) // => 100
49 *
50 * // Use with complex types
51 * interface Config {
52 * timeout: number
53 * retries: number
54 * }
55 *
56 * const config: MutableRef.MutableRef<Config> = MutableRef.make({
57 * timeout: 5000,
58 * retries: 3
59 * })
60 *
61 * // Update through the interface
62 * config.current = { timeout: 10000, retries: 5 }
63 *
64 * config.current // => { timeout: 10000, retries: 5 }
65 * ```
66 *
67 * @category models
68 * @since 2.0.0
69 */
70export interface MutableRef<out T> extends Pipeable, Inspectable {
71 readonly [TypeId]: typeof TypeId
72 current: T
73}
74
75const MutableRefProto: Omit<MutableRef<unknown>, "current"> = {
76 [TypeId]: TypeId,
77 ...PipeInspectableProto,
78 toJSON<A>(this: MutableRef<A>) {
79 return {
80 _id: "MutableRef",
81 current: toJson(this.current)
82 }
83 }
84}
85
86/**
87 * Creates a new MutableRef with the specified initial value.
88 *
89 * **When to use**
90 *
91 * Use to create a synchronous `MutableRef` initialized with a value.
92 *
93 * **Example** (Creating mutable refs)
94 *
95 * ```ts import.meta.vitest
96 * import { MutableRef } from "effect"
97 *
98 * // Create a counter reference
99 * const counter = MutableRef.make(0)
100 *
101 * MutableRef.get(counter) // => 0
102 *
103 * // Create a configuration reference
104 * const config = MutableRef.make({ debug: false, timeout: 5000 })
105 *
106 * MutableRef.get(config) // => { debug: false, timeout: 5000 }
107 *
108 * // Create a string reference
109 * const status = MutableRef.make("idle")
110 * MutableRef.set(status, "running")
111 *
112 * MutableRef.get(status) // => "running"
113 * ```
114 *
115 * @category constructors
116 * @since 2.0.0
117 */
118export const make = <T>(value: T): MutableRef<T> => {
119 const ref = Object.create(MutableRefProto)
120 ref.current = value
121 return ref
122}
123
124/**
125 * Sets the value to newValue atomically if the current value equals oldValue.
126 * Returns true if the value was updated, false otherwise.
127 * Uses Effect's Equal interface for value comparison.
128 *
129 * **When to use**
130 *
131 * Use to replace a `MutableRef` value only when the current value still matches
132 * an expected value.
133 *
134 * **Example** (Comparing and setting values)
135 *
136 * ```ts import.meta.vitest
137 * import { MutableRef } from "effect"
138 *
139 * const ref = MutableRef.make("initial")
140 *
141 * // Successful compare and set
142 * const updated = MutableRef.compareAndSet(ref, "initial", "updated")
143 *
144 * updated // => true
145 * MutableRef.get(ref) // => "updated"
146 *
147 * // Failed compare and set (value doesn't match)
148 * const failed = MutableRef.compareAndSet(ref, "initial", "failed")
149 *
150 * failed // => false
151 * MutableRef.get(ref) // => "updated"
152 *
153 * // Thread-safe counter increment
154 * const counter = MutableRef.make(5)
155 * let current: number
156 * do {
157 * current = MutableRef.get(counter)
158 * } while (!MutableRef.compareAndSet(counter, current, current + 1))
159 *
160 * MutableRef.get(counter) // => 6
161 *
162 * // Pipe-able version
163 * const casUpdate = MutableRef.compareAndSet("updated", "final")
164 *
165 * casUpdate(ref) // => true
166 * MutableRef.get(ref) // => "final"
167 * ```
168 *
169 * @category mutations
170 * @since 2.0.0
171 */
172export const compareAndSet: {
173 <T>(oldValue: T, newValue: T): (self: MutableRef<T>) => boolean
174 <T>(self: MutableRef<T>, oldValue: T, newValue: T): boolean
175} = Dual.dual<
176 <T>(oldValue: T, newValue: T) => (self: MutableRef<T>) => boolean,
177 <T>(self: MutableRef<T>, oldValue: T, newValue: T) => boolean
178>(3, (self, oldValue, newValue) => {
179 if (Equal.equals(oldValue, self.current)) {
180 self.current = newValue
181 return true
182 }
183 return false
184})
185
186/**
187 * Decrements a numeric MutableRef by 1 and returns the reference.
188 *
189 * **When to use**
190 *
191 * Use when you need an in-place `MutableRef` decrement that returns the same
192 * `MutableRef`.
193 *
194 * **Example** (Decrementing numeric refs)
195 *
196 * ```ts import.meta.vitest
197 * import { MutableRef } from "effect"
198 *
199 * const counter = MutableRef.make(5)
200 *
201 * // Decrement the counter
202 * MutableRef.decrement(counter)
203 *
204 * MutableRef.get(counter) // => 4
205 *
206 * // Chain operations
207 * MutableRef.decrement(counter)
208 * MutableRef.decrement(counter)
209 *
210 * MutableRef.get(counter) // => 2
211 *
212 * // Useful for countdown scenarios
213 * const countdown = MutableRef.make(10)
214 * while (MutableRef.get(countdown) > 0) {
215 * MutableRef.decrement(countdown)
216 * }
217 *
218 * MutableRef.get(countdown) // => 0
219 * ```
220 *
221 * @category mutations
222 * @since 2.0.0
223 */
224export const decrement = (self: MutableRef<number>): MutableRef<number> => update(self, (n) => n - 1)
225
226/**
227 * Decrements a numeric MutableRef by 1 and returns the new value.
228 *
229 * **When to use**
230 *
231 * Use to decrement a numeric `MutableRef` and immediately read the updated
232 * value.
233 *
234 * **Example** (Decrementing and reading refs)
235 *
236 * ```ts import.meta.vitest
237 * import { MutableRef } from "effect"
238 *
239 * const counter = MutableRef.make(5)
240 *
241 * // Decrement and get the new value
242 * const newValue = MutableRef.decrementAndGet(counter)
243 *
244 * newValue // => 4
245 * MutableRef.get(counter) // => 4
246 *
247 * // Use in expressions
248 * const lives = MutableRef.make(3)
249 * const message = `Lives remaining: ${MutableRef.decrementAndGet(lives)}`
250 *
251 * message // => "Lives remaining: 2"
252 *
253 * // Conditional logic based on decremented value
254 * const attempts = MutableRef.make(3)
255 * let retries = 0
256 * while (MutableRef.decrementAndGet(attempts) >= 0) {
257 * retries += 1
258 * }
259 *
260 * retries // => 3
261 * MutableRef.get(attempts) // => -1
262 * ```
263 *
264 * @category mutations
265 * @since 2.0.0
266 */
267export const decrementAndGet = (self: MutableRef<number>): number => updateAndGet(self, (n) => n - 1)
268
269/**
270 * Gets the current value of the MutableRef.
271 *
272 * **When to use**
273 *
274 * Use to read the current `MutableRef` value without mutating it.
275 *
276 * **Example** (Reading current values)
277 *
278 * ```ts import.meta.vitest
279 * import { MutableRef } from "effect"
280 *
281 * const ref = MutableRef.make("hello")
282 *
283 * MutableRef.get(ref) // => "hello"
284 *
285 * MutableRef.set(ref, "world")
286 *
287 * MutableRef.get(ref) // => "world"
288 *
289 * // Reading complex objects
290 * const config = MutableRef.make({ port: 3000, host: "localhost" })
291 * const currentConfig = MutableRef.get(config)
292 *
293 * currentConfig // => { port: 3000, host: "localhost" }
294 *
295 * // Multiple reads return the same value
296 * const value1 = MutableRef.get(ref)
297 * const value2 = MutableRef.get(ref)
298 *
299 * value1 === value2 // => true
300 * ```
301 *
302 * @category getters
303 * @since 2.0.0
304 */
305export const get = <T>(self: MutableRef<T>): T => self.current
306
307/**
308 * Decrements a numeric MutableRef by 1 and returns the previous value.
309 *
310 * **When to use**
311 *
312 * Use to read the current numeric `MutableRef` value before decrementing it.
313 *
314 * **Example** (Reading before decrementing)
315 *
316 * ```ts import.meta.vitest
317 * import { MutableRef } from "effect"
318 *
319 * const counter = MutableRef.make(5)
320 *
321 * // Get current value and then decrement
322 * const previousValue = MutableRef.getAndDecrement(counter)
323 *
324 * previousValue // => 5
325 * MutableRef.get(counter) // => 4
326 *
327 * // Useful for processing where you need the original value
328 * const itemsLeft = MutableRef.make(10)
329 * const processedItems: Array<number> = []
330 * while (MutableRef.get(itemsLeft) > 0) {
331 * const currentItem = MutableRef.getAndDecrement(itemsLeft)
332 * processedItems.push(currentItem)
333 * }
334 *
335 * processedItems // => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
336 * MutableRef.get(itemsLeft) // => 0
337 *
338 * // Post-decrement semantics (like i-- in other languages)
339 * const index = MutableRef.make(3)
340 * const currentIndex = MutableRef.getAndDecrement(index)
341 * const nextIndex = MutableRef.get(index)
342 *
343 * currentIndex // => 3
344 * nextIndex // => 2
345 * ```
346 *
347 * @category mutations
348 * @since 2.0.0
349 */
350export const getAndDecrement = (self: MutableRef<number>): number => getAndUpdate(self, (n) => n - 1)
351
352/**
353 * Increments a numeric MutableRef by 1 and returns the previous value.
354 *
355 * **When to use**
356 *
357 * Use to read the current numeric `MutableRef` value before incrementing it.
358 *
359 * **Example** (Reading before incrementing)
360 *
361 * ```ts import.meta.vitest
362 * import { MutableRef } from "effect"
363 *
364 * const counter = MutableRef.make(5)
365 *
366 * // Get current value and then increment
367 * const previousValue = MutableRef.getAndIncrement(counter)
368 *
369 * previousValue // => 5
370 * MutableRef.get(counter) // => 6
371 *
372 * // Useful for ID generation
373 * const idGenerator = MutableRef.make(0)
374 * const getId = () => MutableRef.getAndIncrement(idGenerator)
375 * const ids = [getId(), getId(), getId()]
376 *
377 * ids // => [0, 1, 2]
378 *
379 * // Post-increment semantics (like i++ in other languages)
380 * const position = MutableRef.make(0)
381 * const currentPos = MutableRef.getAndIncrement(position)
382 * const nextPos = MutableRef.get(position)
383 *
384 * currentPos // => 0
385 * nextPos // => 1
386 *
387 * // Useful for iteration counters
388 * const iterations = MutableRef.make(0)
389 * const visited: Array<number> = []
390 * while (MutableRef.get(iterations) < 5) {
391 * const iteration = MutableRef.getAndIncrement(iterations)
392 * visited.push(iteration)
393 * }
394 *
395 * visited // => [0, 1, 2, 3, 4]
396 * MutableRef.get(iterations) // => 5
397 * ```
398 *
399 * @category mutations
400 * @since 2.0.0
401 */
402export const getAndIncrement = (self: MutableRef<number>): number => getAndUpdate(self, (n) => n + 1)
403
404/**
405 * Sets the MutableRef to a new value and returns the previous value.
406 *
407 * **When to use**
408 *
409 * Use to replace the current `MutableRef` value while keeping the previous
410 * value.
411 *
412 * **Example** (Reading before setting)
413 *
414 * ```ts import.meta.vitest
415 * import { MutableRef } from "effect"
416 *
417 * const ref = MutableRef.make("old")
418 *
419 * // Set new value and get the previous one
420 * const previous = MutableRef.getAndSet(ref, "new")
421 *
422 * previous // => "old"
423 * MutableRef.get(ref) // => "new"
424 *
425 * // Swapping values
426 * const counter = MutableRef.make(5)
427 * const oldValue = MutableRef.getAndSet(counter, 10)
428 * const newValue = MutableRef.get(counter)
429 *
430 * oldValue // => 5
431 * newValue // => 10
432 *
433 * // Pipe-able version
434 * const setValue = MutableRef.getAndSet("final")
435 * const previousValue = setValue(ref)
436 *
437 * previousValue // => "new"
438 * MutableRef.get(ref) // => "final"
439 *
440 * // Useful for atomic swaps in algorithms
441 * const buffer = MutableRef.make<Array<string>>(["a", "b", "c"])
442 * const oldBuffer = MutableRef.getAndSet(buffer, [])
443 *
444 * oldBuffer // => ["a", "b", "c"]
445 * MutableRef.get(buffer) // => []
446 * ```
447 *
448 * @category mutations
449 * @since 2.0.0
450 */
451export const getAndSet: {
452 <T>(value: T): (self: MutableRef<T>) => T
453 <T>(self: MutableRef<T>, value: T): T
454} = Dual.dual<
455 <T>(value: T) => (self: MutableRef<T>) => T,
456 <T>(self: MutableRef<T>, value: T) => T
457>(2, (self, value) => {
458 const ret = self.current
459 self.current = value
460 return ret
461})
462
463/**
464 * Updates the MutableRef with the result of applying a function to its current value,
465 * and returns the previous value.
466 *
467 * **When to use**
468 *
469 * Use to transform the current `MutableRef` value while keeping the previous
470 * value.
471 *
472 * **Example** (Reading before updating)
473 *
474 * ```ts import.meta.vitest
475 * import { MutableRef } from "effect"
476 *
477 * const counter = MutableRef.make(5)
478 *
479 * // Increment and get the old value
480 * const oldValue = MutableRef.getAndUpdate(counter, (n) => n + 1)
481 *
482 * oldValue // => 5
483 * MutableRef.get(counter) // => 6
484 *
485 * // Double the value and get the previous one
486 * const previous = MutableRef.getAndUpdate(counter, (n) => n * 2)
487 *
488 * previous // => 6
489 * MutableRef.get(counter) // => 12
490 *
491 * // Transform string and get old value
492 * const message = MutableRef.make("hello")
493 * const oldMessage = MutableRef.getAndUpdate(message, (s) => s.toUpperCase())
494 *
495 * oldMessage // => "hello"
496 * MutableRef.get(message) // => "HELLO"
497 *
498 * // Pipe-able version
499 * const addOne = MutableRef.getAndUpdate((n: number) => n + 1)
500 * const result = addOne(counter)
501 *
502 * result // => 12
503 * MutableRef.get(counter) // => 13
504 *
505 * // Useful for implementing atomic operations
506 * const list = MutableRef.make<Array<number>>([1, 2, 3])
507 * const oldList = MutableRef.getAndUpdate(list, (arr) => [...arr, 4])
508 *
509 * oldList // => [1, 2, 3]
510 * MutableRef.get(list) // => [1, 2, 3, 4]
511 * ```
512 *
513 * @category mutations
514 * @since 2.0.0
515 */
516export const getAndUpdate: {
517 <T>(f: (value: T) => T): (self: MutableRef<T>) => T
518 <T>(self: MutableRef<T>, f: (value: T) => T): T
519} = Dual.dual<
520 <T>(f: (value: T) => T) => (self: MutableRef<T>) => T,
521 <T>(self: MutableRef<T>, f: (value: T) => T) => T
522>(2, (self, f) => getAndSet(self, f(get(self))))
523
524/**
525 * Increments a numeric MutableRef by 1 and returns the reference.
526 *
527 * **When to use**
528 *
529 * Use when you need an in-place `MutableRef` increment that returns the same
530 * `MutableRef`.
531 *
532 * **Example** (Incrementing numeric refs)
533 *
534 * ```ts import.meta.vitest
535 * import { MutableRef } from "effect"
536 *
537 * const counter = MutableRef.make(5)
538 *
539 * // Increment the counter
540 * MutableRef.increment(counter)
541 *
542 * MutableRef.get(counter) // => 6
543 *
544 * // Chain operations
545 * MutableRef.increment(counter)
546 * MutableRef.increment(counter)
547 *
548 * MutableRef.get(counter) // => 8
549 *
550 * // Useful for simple counting
551 * const visits = MutableRef.make(0)
552 * MutableRef.increment(visits) // User visited
553 * MutableRef.increment(visits) // Another visit
554 *
555 * MutableRef.get(visits) // => 2
556 *
557 * // Returns the reference for chaining
558 * const result = MutableRef.increment(counter)
559 *
560 * result === counter // => true
561 * MutableRef.get(counter) // => 9
562 * ```
563 *
564 * @category mutations
565 * @since 2.0.0
566 */
567export const increment = (self: MutableRef<number>): MutableRef<number> => update(self, (n) => n + 1)
568
569/**
570 * Increments a numeric MutableRef by 1 and returns the new value.
571 *
572 * **When to use**
573 *
574 * Use to increment a numeric `MutableRef` and immediately read the updated
575 * value.
576 *
577 * **Example** (Incrementing and reading refs)
578 *
579 * ```ts import.meta.vitest
580 * import { MutableRef } from "effect"
581 *
582 * const counter = MutableRef.make(5)
583 *
584 * // Increment and get the new value
585 * const newValue = MutableRef.incrementAndGet(counter)
586 *
587 * newValue // => 6
588 * MutableRef.get(counter) // => 6
589 *
590 * // Use in expressions
591 * const score = MutableRef.make(100)
592 * const message = `New score: ${MutableRef.incrementAndGet(score)}`
593 *
594 * message // => "New score: 101"
595 *
596 * // Pre-increment semantics (like ++i in other languages)
597 * const level = MutableRef.make(0)
598 * const nextLevel = MutableRef.incrementAndGet(level)
599 *
600 * nextLevel // => 1
601 *
602 * // Conditional logic based on incremented value
603 * const attempts = MutableRef.make(0)
604 * const tooManyAttempts = MutableRef.incrementAndGet(attempts) > 3
605 *
606 * tooManyAttempts // => false
607 * MutableRef.get(attempts) // => 1
608 * ```
609 *
610 * @category mutations
611 * @since 2.0.0
612 */
613export const incrementAndGet = (self: MutableRef<number>): number => updateAndGet(self, (n) => n + 1)
614
615/**
616 * Sets the MutableRef to a new value and returns the reference.
617 *
618 * **When to use**
619 *
620 * Use when you need an in-place `MutableRef` replacement that returns the same
621 * `MutableRef`.
622 *
623 * **Example** (Setting values)
624 *
625 * ```ts import.meta.vitest
626 * import { MutableRef } from "effect"
627 *
628 * const ref = MutableRef.make("initial")
629 *
630 * // Set a new value
631 * MutableRef.set(ref, "updated")
632 *
633 * MutableRef.get(ref) // => "updated"
634 *
635 * // Chain set operations (since it returns the ref)
636 * const result = MutableRef.set(ref, "final")
637 *
638 * result === ref // => true
639 * MutableRef.get(ref) // => "final"
640 *
641 * // Set complex objects
642 * const config = MutableRef.make({ debug: false, verbose: false })
643 * MutableRef.set(config, { debug: true, verbose: true })
644 *
645 * MutableRef.get(config) // => { debug: true, verbose: true }
646 *
647 * // Pipe-able version
648 * const setValue = MutableRef.set("new value")
649 * setValue(ref)
650 *
651 * MutableRef.get(ref) // => "new value"
652 *
653 * // Useful for state management
654 * const state = MutableRef.make<"idle" | "loading" | "success" | "error">("idle")
655 * MutableRef.set(state, "loading")
656 * // ... perform async operation
657 * MutableRef.set(state, "success")
658 *
659 * MutableRef.get(state) // => "success"
660 * ```
661 *
662 * @category mutations
663 * @since 2.0.0
664 */
665export const set: {
666 <T>(value: T): (self: MutableRef<T>) => MutableRef<T>
667 <T>(self: MutableRef<T>, value: T): MutableRef<T>
668} = Dual.dual<
669 <T>(value: T) => (self: MutableRef<T>) => MutableRef<T>,
670 <T>(self: MutableRef<T>, value: T) => MutableRef<T>
671>(2, (self, value) => {
672 self.current = value
673 return self
674})
675
676/**
677 * Sets the MutableRef to a new value and returns the new value.
678 *
679 * **When to use**
680 *
681 * Use to replace the current `MutableRef` value and immediately read the
682 * replacement.
683 *
684 * **Example** (Setting and reading values)
685 *
686 * ```ts import.meta.vitest
687 * import { MutableRef } from "effect"
688 *
689 * const ref = MutableRef.make("old")
690 *
691 * // Set and get the new value
692 * const newValue = MutableRef.setAndGet(ref, "new")
693 *
694 * newValue // => "new"
695 * MutableRef.get(ref) // => "new"
696 *
697 * // Useful for assignments that need the value
698 * const counter = MutableRef.make(0)
699 * const currentValue = MutableRef.setAndGet(counter, 42)
700 *
701 * currentValue // => 42
702 *
703 * // Pipe-able version
704 * const setValue = MutableRef.setAndGet("final")
705 * const result = setValue(ref)
706 *
707 * result // => "final"
708 *
709 * // Difference from set: returns value instead of reference
710 * const ref1 = MutableRef.make(1)
711 * const returnedRef = MutableRef.set(ref1, 2) // Returns MutableRef
712 * const returnedValue = MutableRef.setAndGet(ref1, 3) // Returns value
713 *
714 * returnedRef === ref1 // => true
715 * returnedValue // => 3
716 * MutableRef.get(ref1) // => 3
717 * ```
718 *
719 * @category mutations
720 * @since 2.0.0
721 */
722export const setAndGet: {
723 <T>(value: T): (self: MutableRef<T>) => T
724 <T>(self: MutableRef<T>, value: T): T
725} = Dual.dual<
726 <T>(value: T) => (self: MutableRef<T>) => T,
727 <T>(self: MutableRef<T>, value: T) => T
728>(2, (self, value) => {
729 self.current = value
730 return self.current
731})
732
733/**
734 * Updates the MutableRef with the result of applying a function to its current value,
735 * and returns the reference.
736 *
737 * **When to use**
738 *
739 * Use when you need an in-place `MutableRef` value transformation that returns
740 * the same `MutableRef`.
741 *
742 * **Example** (Updating values)
743 *
744 * ```ts import.meta.vitest
745 * import { MutableRef } from "effect"
746 *
747 * const counter = MutableRef.make(5)
748 *
749 * // Increment the counter
750 * MutableRef.update(counter, (n) => n + 1)
751 *
752 * MutableRef.get(counter) // => 6
753 *
754 * // Chain updates (since it returns the ref)
755 * const result = MutableRef.update(counter, (n) => n * 2)
756 *
757 * result === counter // => true
758 * MutableRef.get(counter) // => 12
759 *
760 * // Transform string
761 * const message = MutableRef.make("hello")
762 * MutableRef.update(message, (s) => s.toUpperCase())
763 *
764 * MutableRef.get(message) // => "HELLO"
765 *
766 * // Update complex objects
767 * const user = MutableRef.make({ name: "Alice", age: 30 })
768 * MutableRef.update(user, (u) => ({ ...u, age: u.age + 1 }))
769 *
770 * MutableRef.get(user) // => { name: "Alice", age: 31 }
771 *
772 * // Pipe-able version
773 * const double = MutableRef.update((n: number) => n * 2)
774 * double(counter)
775 *
776 * MutableRef.get(counter) // => 24
777 *
778 * // Array operations
779 * const list = MutableRef.make<Array<number>>([1, 2, 3])
780 * MutableRef.update(list, (arr) => [...arr, 4])
781 *
782 * MutableRef.get(list) // => [1, 2, 3, 4]
783 * ```
784 *
785 * @category mutations
786 * @since 2.0.0
787 */
788export const update: {
789 <T>(f: (value: T) => T): (self: MutableRef<T>) => MutableRef<T>
790 <T>(self: MutableRef<T>, f: (value: T) => T): MutableRef<T>
791} = Dual.dual<
792 <T>(f: (value: T) => T) => (self: MutableRef<T>) => MutableRef<T>,
793 <T>(self: MutableRef<T>, f: (value: T) => T) => MutableRef<T>
794>(2, (self, f) => set(self, f(get(self))))
795
796/**
797 * Updates the MutableRef with the result of applying a function to its current value,
798 * and returns the new value.
799 *
800 * **When to use**
801 *
802 * Use to transform the current `MutableRef` value and immediately read the
803 * updated value.
804 *
805 * **Example** (Updating and reading values)
806 *
807 * ```ts import.meta.vitest
808 * import { MutableRef } from "effect"
809 *
810 * const counter = MutableRef.make(5)
811 *
812 * // Increment and get the new value
813 * const newValue = MutableRef.updateAndGet(counter, (n) => n + 1)
814 *
815 * newValue // => 6
816 * MutableRef.get(counter) // => 6
817 *
818 * // Double the value and get the result
819 * const doubled = MutableRef.updateAndGet(counter, (n) => n * 2)
820 *
821 * doubled // => 12
822 *
823 * // Transform string and get result
824 * const message = MutableRef.make("hello")
825 * const upperCase = MutableRef.updateAndGet(message, (s) => s.toUpperCase())
826 *
827 * upperCase // => "HELLO"
828 *
829 * // Pipe-able version
830 * const increment = MutableRef.updateAndGet((n: number) => n + 1)
831 * const result = increment(counter)
832 *
833 * result // => 13
834 *
835 * // Useful for calculations that need the result
836 * const score = MutableRef.make(100)
837 * const bonus = 50
838 * const newScore = MutableRef.updateAndGet(score, (s) => s + bonus)
839 *
840 * newScore // => 150
841 *
842 * // Array transformations
843 * const list = MutableRef.make<Array<number>>([1, 2, 3])
844 * const newList = MutableRef.updateAndGet(list, (arr) => arr.map((x) => x * 2))
845 *
846 * newList // => [2, 4, 6]
847 * MutableRef.get(list) // => [2, 4, 6]
848 * ```
849 *
850 * @category mutations
851 * @since 2.0.0
852 */
853export const updateAndGet: {
854 <T>(f: (value: T) => T): (self: MutableRef<T>) => T
855 <T>(self: MutableRef<T>, f: (value: T) => T): T
856} = Dual.dual<
857 <T>(f: (value: T) => T) => (self: MutableRef<T>) => T,
858 <T>(self: MutableRef<T>, f: (value: T) => T) => T
859>(2, (self, f) => setAndGet(self, f(get(self))))
860
861/**
862 * Switches a boolean `MutableRef` between `true` and `false`, then returns the
863 * reference.
864 *
865 * **When to use**
866 *
867 * Use when you need an in-place boolean `MutableRef` toggle that returns the
868 * same `MutableRef`.
869 *
870 * **Example** (Toggling boolean refs)
871 *
872 * ```ts import.meta.vitest
873 * import { MutableRef } from "effect"
874 *
875 * const flag = MutableRef.make(false)
876 *
877 * // Toggle the flag
878 * MutableRef.toggle(flag)
879 *
880 * MutableRef.get(flag) // => true
881 *
882 * // Toggle again
883 * MutableRef.toggle(flag)
884 *
885 * MutableRef.get(flag) // => false
886 *
887 * // Useful for state switches
888 * const isVisible = MutableRef.make(true)
889 * MutableRef.toggle(isVisible) // Hide
890 *
891 * MutableRef.get(isVisible) // => false
892 *
893 * // Toggle button implementation
894 * const darkMode = MutableRef.make(false)
895 * const toggleDarkMode = () => {
896 * MutableRef.toggle(darkMode)
897 * return MutableRef.get(darkMode) ? "ON" : "OFF"
898 * }
899 *
900 * toggleDarkMode() // => "ON"
901 * toggleDarkMode() // => "OFF"
902 *
903 * // Returns the reference for chaining
904 * const result = MutableRef.toggle(flag)
905 *
906 * result === flag // => true
907 * MutableRef.get(flag) // => true
908 * ```
909 *
910 * @category mutations
911 * @since 2.0.0
912 */
913export const toggle = (self: MutableRef<boolean>): MutableRef<boolean> => update(self, (_) => !_)