@@ -103,7 +103,7 @@ MP_DEFINE_CONST_OBJ_TYPE(pb_type_async,
103103 * Returns an awaitable operation if the runloop is active, or awaits the
104104 * operation here and now.
105105 *
106- * @param [in] config Configuration of the operation
106+ * @param [in] config Configuration of the operation. NB: State will not be reset.
107107 * @param [in, out] prev Candidate iterable object that might be re-used, otherwise assigned newly allocated object.
108108 * @param [in] stop_prev Whether to stop ongoing awaitable if it is active.
109109 * @returns An awaitable if the runloop is active, otherwise the mapped return value.
@@ -147,3 +147,57 @@ mp_obj_t pb_type_async_wait_or_await(pb_type_async_t *config, pb_type_async_t **
147147 pb_assert (err );
148148 return config -> return_map ? config -> return_map (config -> parent_obj ) : mp_const_none ;
149149}
150+
151+ /**
152+ * Iteration for a constant awaitable that yields once before returning.
153+ *
154+ * This is different from omitting iter_once to achieve a single yield, since
155+ * that special case cannot have a return value.
156+ *
157+ * @param [in] state Protothread state.
158+ * @param [in] parent_obj The constant.
159+ */
160+ static pbio_error_t pb_type_async_constant_iter_once (pbio_os_state_t * state , mp_obj_t parent_obj ) {
161+ PBIO_OS_ASYNC_BEGIN (state );
162+ PBIO_OS_AWAIT_ONCE (state );
163+ PBIO_OS_ASYNC_END (PBIO_SUCCESS );
164+ }
165+
166+ /**
167+ * Return map for a constant awaitable.
168+ *
169+ * @param [in] parent_obj The constant.
170+ * @returns The same constant.
171+ */
172+ static mp_obj_t pb_type_async_constant_return_map (mp_obj_t parent_obj ) {
173+ return parent_obj ;
174+ }
175+
176+ /**
177+ * Returns an awaitable operation that yields once and then returns a constant
178+ * result. If the runloop is not active, this just returns the given value.
179+ *
180+ * Can be used to return constants from functions that still need to be
181+ * awaitable for other reasons.
182+ *
183+ * @param [in] ret_obj Return result.
184+ * @param [in, out] prev Candidate iterable object that might be
185+ * re-used, otherwise assigned newly allocated object.
186+ * @returns An awaitable if the runloop is active, otherwise the constant return value.
187+ */
188+ mp_obj_t pb_type_async_return_constant (mp_obj_t ret_obj , pb_type_async_t * * prev ) {
189+
190+ // In synchronous mode, return right away.
191+ if (!pb_module_tools_run_loop_is_active ()) {
192+ return ret_obj ;
193+ }
194+
195+ // Async case returns soon.
196+ pb_type_async_t config = {
197+ .parent_obj = ret_obj ,
198+ .iter_once = pb_type_async_constant_iter_once ,
199+ .return_map = pb_type_async_constant_return_map ,
200+ .state = 0 ,
201+ };
202+ return pb_type_async_wait_or_await (& config , prev , false);
203+ }
0 commit comments