effect 3.5.8 → 3.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Micro.ts CHANGED
@@ -562,6 +562,7 @@ export const envUnsafeMakeEmpty = (): Env<never> => {
562
562
  const refs = Object.create(null)
563
563
  refs[currentAbortController.key] = controller
564
564
  refs[currentAbortSignal.key] = controller.signal
565
+ refs[currentScheduler.key] = new MicroSchedulerDefault()
565
566
  return envMake(refs)
566
567
  }
567
568
 
@@ -733,6 +734,79 @@ export const provideServiceEffect: {
733
734
  ): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
734
735
  )
735
736
 
737
+ // ----------------------------------------------------------------------------
738
+ // scheduler
739
+ // ----------------------------------------------------------------------------
740
+
741
+ /**
742
+ * @since 3.5.9
743
+ * @experimental
744
+ * @category scheduler
745
+ */
746
+ export interface MicroScheduler {
747
+ readonly scheduleTask: (task: () => void, priority: number) => void
748
+ readonly shouldYield: (env: Env<unknown>) => boolean
749
+ readonly flush: () => void
750
+ }
751
+
752
+ const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
753
+
754
+ /**
755
+ * @since 3.5.9
756
+ * @experimental
757
+ * @category scheduler
758
+ */
759
+ export class MicroSchedulerDefault implements MicroScheduler {
760
+ private tasks: Array<() => void> = []
761
+ private running = false
762
+
763
+ /**
764
+ * @since 3.5.9
765
+ */
766
+ scheduleTask(task: () => void, _priority: number) {
767
+ this.tasks.push(task)
768
+ if (!this.running) {
769
+ this.running = true
770
+ setImmediate(this.afterScheduled)
771
+ }
772
+ }
773
+
774
+ /**
775
+ * @since 3.5.9
776
+ */
777
+ afterScheduled = () => {
778
+ this.running = false
779
+ this.runTasks()
780
+ }
781
+
782
+ /**
783
+ * @since 3.5.9
784
+ */
785
+ runTasks() {
786
+ const tasks = this.tasks
787
+ this.tasks = []
788
+ for (let i = 0, len = tasks.length; i < len; i++) {
789
+ tasks[i]()
790
+ }
791
+ }
792
+
793
+ /**
794
+ * @since 3.5.9
795
+ */
796
+ shouldYield(_env: Env<unknown>) {
797
+ return false
798
+ }
799
+
800
+ /**
801
+ * @since 3.5.9
802
+ */
803
+ flush() {
804
+ while (this.tasks.length > 0) {
805
+ this.runTasks()
806
+ }
807
+ }
808
+ }
809
+
736
810
  // ========================================================================
737
811
  // Env refs
738
812
  // ========================================================================
@@ -809,6 +883,16 @@ const currentInterruptible: EnvRef<boolean> = envRefMake(
809
883
  () => true
810
884
  )
811
885
 
886
+ /**
887
+ * @since 3.4.0
888
+ * @experimental
889
+ * @category environment refs
890
+ */
891
+ export const currentScheduler: EnvRef<MicroScheduler> = envRefMake(
892
+ "effect/Micro/currentScheduler",
893
+ () => new MicroSchedulerDefault()
894
+ )
895
+
812
896
  /**
813
897
  * If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
814
898
  * api to control the concurrency of that `Micro` when it is run.
@@ -879,8 +963,9 @@ const unsafeMakeOptions = <R, A, E>(
879
963
  if (microDepthState.depth === 1) {
880
964
  microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield)
881
965
  }
882
- if (microDepthState.depth >= microDepthState.maxDepthBeforeYield) {
883
- yieldAdd(() => execute(env, onExit))
966
+ const scheduler = env.refs[currentScheduler.key] as MicroScheduler
967
+ if (microDepthState.depth >= microDepthState.maxDepthBeforeYield || scheduler.shouldYield(env)) {
968
+ scheduler.scheduleTask(() => execute(env, onExit), 0)
884
969
  } else {
885
970
  try {
886
971
  run(env, onExit)
@@ -1200,34 +1285,21 @@ export const tryPromise = <A, E>(options: {
1200
1285
  }
1201
1286
  })
1202
1287
 
1203
- const yieldState: {
1204
- tasks: Array<() => void>
1205
- working: boolean
1206
- } = globalValue("effect/Micro/yieldState", () => ({
1207
- tasks: [],
1208
- working: false
1209
- }))
1210
-
1211
- const yieldRunTasks = () => {
1212
- const tasks = yieldState.tasks
1213
- yieldState.tasks = []
1214
- for (let i = 0, len = tasks.length; i < len; i++) {
1215
- tasks[i]()
1216
- }
1217
- }
1218
-
1219
- const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
1220
-
1221
- const yieldAdd = (task: () => void) => {
1222
- yieldState.tasks.push(task)
1223
- if (!yieldState.working) {
1224
- yieldState.working = true
1225
- setImmediate(() => {
1226
- yieldState.working = false
1227
- yieldRunTasks()
1228
- })
1229
- }
1230
- }
1288
+ /**
1289
+ * Pause the execution of the current `Micro` effect, and resume it on the next
1290
+ * iteration of the event loop.
1291
+ *
1292
+ * You can specify a priority for the task, which will determine when it is
1293
+ * executed relative to other tasks.
1294
+ *
1295
+ * @since 3.4.0
1296
+ * @experimental
1297
+ * @category constructors
1298
+ */
1299
+ export const yieldWithPriority = (priority: number): Micro<void> =>
1300
+ make(function(env, onExit) {
1301
+ envGet(env, currentScheduler).scheduleTask(() => onExit(exitVoid), priority)
1302
+ })
1231
1303
 
1232
1304
  /**
1233
1305
  * Pause the execution of the current `Micro` effect, and resume it on the next
@@ -1237,9 +1309,7 @@ const yieldAdd = (task: () => void) => {
1237
1309
  * @experimental
1238
1310
  * @category constructors
1239
1311
  */
1240
- export const yieldNow: Micro<void> = make(function(_env, onExit) {
1241
- yieldAdd(() => onExit(exitVoid))
1242
- })
1312
+ export const yieldNow: Micro<void> = yieldWithPriority(0)
1243
1313
 
1244
1314
  /**
1245
1315
  * Flush any yielded effects that are waiting to be executed.
@@ -1248,10 +1318,9 @@ export const yieldNow: Micro<void> = make(function(_env, onExit) {
1248
1318
  * @experimental
1249
1319
  * @category constructors
1250
1320
  */
1251
- export const yieldFlush: Micro<void> = sync(function() {
1252
- while (yieldState.tasks.length > 0) {
1253
- yieldRunTasks()
1254
- }
1321
+ export const yieldFlush: Micro<void> = make(function(env, onExit) {
1322
+ envGet(env, currentScheduler).flush()
1323
+ onExit(exitVoid)
1255
1324
  })
1256
1325
 
1257
1326
  /**
@@ -3687,11 +3756,11 @@ export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never,
3687
3756
  map[currentAbortSignal.key] = handle._controller.signal
3688
3757
  return map
3689
3758
  })
3690
- yieldAdd(() => {
3759
+ envGet(env, currentScheduler).scheduleTask(() => {
3691
3760
  self[runSymbol](nextEnv, (exit) => {
3692
3761
  handle.emit(exit)
3693
3762
  })
3694
- })
3763
+ }, 0)
3695
3764
  onExit(Either.right(handle))
3696
3765
  })
3697
3766
 
@@ -3714,11 +3783,11 @@ export const forkDaemon = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, n
3714
3783
  map[currentAbortSignal.key] = controller.signal
3715
3784
  return map
3716
3785
  })
3717
- yieldAdd(() => {
3786
+ envGet(env, currentScheduler).scheduleTask(() => {
3718
3787
  self[runSymbol](nextEnv, (exit) => {
3719
3788
  handle.emit(exit)
3720
3789
  })
3721
- })
3790
+ }, 0)
3722
3791
  onExit(Either.right(handle))
3723
3792
  })
3724
3793
 
@@ -3790,12 +3859,14 @@ export const runFork = <A, E>(
3790
3859
  effect: Micro<A, E>,
3791
3860
  options?: {
3792
3861
  readonly signal?: AbortSignal | undefined
3862
+ readonly scheduler?: MicroScheduler | undefined
3793
3863
  } | undefined
3794
3864
  ): Handle<A, E> => {
3795
3865
  const controller = new AbortController()
3796
3866
  const refs = Object.create(null)
3797
3867
  refs[currentAbortController.key] = controller
3798
3868
  refs[currentAbortSignal.key] = controller.signal
3869
+ refs[currentScheduler.key] = options?.scheduler ?? new MicroSchedulerDefault()
3799
3870
  const env = envMake(refs)
3800
3871
  const handle = new HandleImpl<A, E>(controller.signal, controller)
3801
3872
  effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), (exit) => {
@@ -3826,6 +3897,7 @@ export const runPromiseExit = <A, E>(
3826
3897
  effect: Micro<A, E>,
3827
3898
  options?: {
3828
3899
  readonly signal?: AbortSignal | undefined
3900
+ readonly scheduler?: MicroScheduler | undefined
3829
3901
  } | undefined
3830
3902
  ): Promise<MicroExit<A, E>> =>
3831
3903
  new Promise((resolve, _reject) => {
@@ -3845,6 +3917,7 @@ export const runPromise = <A, E>(
3845
3917
  effect: Micro<A, E>,
3846
3918
  options?: {
3847
3919
  readonly signal?: AbortSignal | undefined
3920
+ readonly scheduler?: MicroScheduler | undefined
3848
3921
  } | undefined
3849
3922
  ): Promise<A> =>
3850
3923
  runPromiseExit(effect, options).then((exit) => {
@@ -3865,10 +3938,9 @@ export const runPromise = <A, E>(
3865
3938
  * @category execution
3866
3939
  */
3867
3940
  export const runSyncExit = <A, E>(effect: Micro<A, E>): MicroExit<A, E> => {
3868
- const handle = runFork(effect)
3869
- while (yieldState.tasks.length > 0) {
3870
- yieldRunTasks()
3871
- }
3941
+ const scheduler = new MicroSchedulerDefault()
3942
+ const handle = runFork(effect, { scheduler })
3943
+ scheduler.flush()
3872
3944
  const exit = handle.unsafePoll()
3873
3945
  if (exit === null) {
3874
3946
  return exitDie(handle)
package/src/Option.ts CHANGED
@@ -1196,7 +1196,7 @@ export const exists: {
1196
1196
  // -------------------------------------------------------------------------------------
1197
1197
 
1198
1198
  /**
1199
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1199
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1200
1200
  *
1201
1201
  * Here's how the do simulation works:
1202
1202
  *
@@ -1244,7 +1244,7 @@ const let_: {
1244
1244
 
1245
1245
  export {
1246
1246
  /**
1247
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1247
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1248
1248
  *
1249
1249
  * Here's how the do simulation works:
1250
1250
  *
@@ -1277,7 +1277,7 @@ export {
1277
1277
  }
1278
1278
 
1279
1279
  /**
1280
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1280
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1281
1281
  *
1282
1282
  * Here's how the do simulation works:
1283
1283
  *
@@ -1319,7 +1319,7 @@ export const bind: {
1319
1319
  } = doNotation.bind<OptionTypeLambda>(map, flatMap)
1320
1320
 
1321
1321
  /**
1322
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1322
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
1323
1323
  *
1324
1324
  * Here's how the do simulation works:
1325
1325
  *
package/src/Stream.ts CHANGED
@@ -5676,11 +5676,11 @@ export const zipWithPreviousAndNext: <A, E, R>(
5676
5676
  export const zipWithIndex: <A, E, R>(self: Stream<A, E, R>) => Stream<[A, number], E, R> = internal.zipWithIndex
5677
5677
 
5678
5678
  // -------------------------------------------------------------------------------------
5679
- // Do notation
5679
+ // do notation
5680
5680
  // -------------------------------------------------------------------------------------
5681
5681
 
5682
5682
  /**
5683
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5683
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5684
5684
  *
5685
5685
  * Here's how the do simulation works:
5686
5686
  *
@@ -5711,7 +5711,7 @@ export const zipWithIndex: <A, E, R>(self: Stream<A, E, R>) => Stream<[A, number
5711
5711
  export const Do: Stream<{}> = internal.Do
5712
5712
 
5713
5713
  /**
5714
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5714
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5715
5715
  *
5716
5716
  * Here's how the do simulation works:
5717
5717
  *
@@ -5787,7 +5787,7 @@ export const bindEffect: {
5787
5787
  } = _groupBy.bindEffect
5788
5788
 
5789
5789
  /**
5790
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5790
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5791
5791
  *
5792
5792
  * Here's how the do simulation works:
5793
5793
  *
@@ -5834,7 +5834,7 @@ const let_: {
5834
5834
 
5835
5835
  export {
5836
5836
  /**
5837
- * The "do simulation" in allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5837
+ * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`.
5838
5838
  *
5839
5839
  * Here's how the do simulation works:
5840
5840
  *
@@ -1,4 +1,4 @@
1
- let moduleVersion = "3.5.8"
1
+ let moduleVersion = "3.5.9"
2
2
 
3
3
  export const getCurrentVersion = () => moduleVersion
4
4