Skip to content

Commit 7c34485

Browse files
committed
pybricks.tools: Add helper for awaitable constants.
We have a few functions with this structure: async def some_func(): if simple_case: # This commits adds a helper to do this: return some_constant return await some_awaitable_operation() Also apply this to the touch sensor value of the Powered Up device.
1 parent 9cd734b commit 7c34485

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

pybricks/tools/pb_type_async.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
}

pybricks/tools/pb_type_async.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ typedef struct {
7575

7676
mp_obj_t pb_type_async_wait_or_await(pb_type_async_t *config, pb_type_async_t **prev, bool stop_prev);
7777

78+
mp_obj_t pb_type_async_return_constant(mp_obj_t ret_obj, pb_type_async_t **prev);
79+
7880
void pb_type_async_schedule_stop_iteration(pb_type_async_t *iter);
7981

8082
#endif // PYBRICKS_INCLUDED_ASYNC_H

0 commit comments

Comments
 (0)