@@ -29,11 +29,11 @@ import kotlinx.coroutines.SupervisorJob
2929internal object CoroutineUtils {
3030
3131 /* *
32- * Creates and returns a new [CoroutineScope] with a [SupervisorJob], [CoroutineName], and
33- * [CoroutineExceptionHandler].
32+ * Creates and returns a new [CoroutineScope] with newly-created [SupervisorJob], [CoroutineName],
33+ * and [CoroutineExceptionHandler] elements .
3434 *
35- * The [CoroutineContext] of the returned [CoroutineScope] will be the given [context], with some
36- * elements unconditionally replaced:
35+ * The [CoroutineContext] of the returned [CoroutineScope] will be the given [context], with the
36+ * following elements unconditionally replaced:
3737 *
3838 * * The [Job] element will be a newly-created [SupervisorJob] with the given [parent]; notably,
3939 * if the given [parent] is null then the parent of the [SupervisorJob] will _also_ be null.
@@ -43,6 +43,18 @@ internal object CoroutineUtils {
4343 * * The [CoroutineExceptionHandler] will be a newly-created instance that simply logs a warning
4444 * message to the given [Logger] and then drops the exception. This prevents any crashing
4545 * coroutines in the returned scope from propagating outside the scope.
46+ *
47+ * @param context The context elements for the returned [CoroutineScope]; note that the [Job],
48+ * [CoroutineName], and [CoroutineExceptionHandler] will be discarded and replaced, as documented
49+ * above.
50+ * @param logger The logger to use to log uncaught exceptions in the [CoroutineExceptionHandler]
51+ * element of the [CoroutineContext] of the returned [CoroutineScope]; also used to calculate the
52+ * [coroutineName] if the given value is null.
53+ * @param parent The parent for the [SupervisorJob] of the [CoroutineContext] of the returned
54+ * [CoroutineScope].
55+ * @param coroutineName The name to specify in the [CoroutineName] element of the
56+ * [CoroutineContext] of the returned [CoroutineScope]; if null, use the [Logger.nameWithId] value
57+ * of the given [logger].
4658 */
4759 fun createSupervisorCoroutineScope (
4860 context : CoroutineContext = EmptyCoroutineContext ,
@@ -60,4 +72,55 @@ internal object CoroutineUtils {
6072 }
6173 }
6274 )
75+
76+ /* *
77+ * Creates and returns a new [CoroutineScope] with newly-created [SupervisorJob], [CoroutineName],
78+ * and [CoroutineExceptionHandler] elements, that is a "child" of the given [parentScope], and
79+ * uses the [CoroutineContext] of the given [parentScope] as its base context.
80+ *
81+ * The [SupervisorJob] of the returned [CoroutineScope] will have its parent set to the [Job] of
82+ * the [CoroutineContext] of the given [parentScope]. If the parent's [Job] is found to be null
83+ * then the parent of the [SupervisorJob] of the returned [CoroutineScope] will also be null.
84+ *
85+ * The [CoroutineContext] of the returned [CoroutineScope] will be that of the [parentScope] plus
86+ * the given [childContextOverrides], plus some elements unconditionally replaced as described in
87+ * [createSupervisorCoroutineScope].
88+ *
89+ * This is a convenience wrapper around [createSupervisorCoroutineScope] that automatically
90+ * extracts the job from the [parentScope] to establish structured concurrency.
91+ *
92+ * @param parentScope The parent scope from which to inherit the context and job.
93+ * @param logger Passed verbatim to [createSupervisorCoroutineScope].
94+ * @param childContextOverrides Additional context elements to add or override from the parent.
95+ * @param coroutineName Passed verbatim to [createSupervisorCoroutineScope].
96+ */
97+ fun createChildSupervisorCoroutineScope (
98+ parentScope : CoroutineScope ,
99+ logger : Logger ,
100+ childContextOverrides : CoroutineContext = EmptyCoroutineContext ,
101+ coroutineName : String? = null
102+ ): CoroutineScope =
103+ createSupervisorCoroutineScope(
104+ context = parentScope.coroutineContext + childContextOverrides,
105+ logger = logger,
106+ parent = parentScope.coroutineContext[Job ],
107+ coroutineName = coroutineName,
108+ )
109+
110+ /* *
111+ * Convenience extension function that simply calls [createChildSupervisorCoroutineScope] with the
112+ * receiver [CoroutineScope] as the first argument.
113+ *
114+ * @receiver Passed to [createChildSupervisorCoroutineScope] as the `parentScope` parameter.
115+ * @param logger Passed to [createChildSupervisorCoroutineScope] as the `logger` parameter.
116+ * @param context Passed to [createChildSupervisorCoroutineScope] as the `childContextOverrides`
117+ * parameter.
118+ * @param coroutineName Passed to [createChildSupervisorCoroutineScope] as the `coroutineName`
119+ * parameter.
120+ */
121+ fun CoroutineScope.createChildSupervisorScope (
122+ logger : Logger ,
123+ context : CoroutineContext = EmptyCoroutineContext ,
124+ coroutineName : String? = null
125+ ): CoroutineScope = createChildSupervisorCoroutineScope(this , logger, context, coroutineName)
63126}
0 commit comments