mirror of
https://github.com/esphome/esphome.git
synced 2026-06-04 17:43:05 +08:00
[api] Fall back to owning types for service array args used after a delay (#16140)
This commit is contained in:
committed by
Jesse Hills
parent
0418f2138a
commit
be84e6c9f4
@@ -72,17 +72,35 @@ APIUnregisterServiceCallAction = api_ns.class_(
|
|||||||
|
|
||||||
UserServiceTrigger = api_ns.class_("UserServiceTrigger", automation.Trigger)
|
UserServiceTrigger = api_ns.class_("UserServiceTrigger", automation.Trigger)
|
||||||
ListEntitiesServicesArgument = api_ns.class_("ListEntitiesServicesArgument")
|
ListEntitiesServicesArgument = api_ns.class_("ListEntitiesServicesArgument")
|
||||||
SERVICE_ARG_NATIVE_TYPES: dict[str, MockObj] = {
|
# Owning element type for each YAML service variable type. Used to derive both
|
||||||
|
# the zero-copy native types and the owning fallback types below.
|
||||||
|
_SERVICE_ARG_SCALAR_TYPES: dict[str, MockObj] = {
|
||||||
"bool": cg.bool_,
|
"bool": cg.bool_,
|
||||||
"int": cg.int32,
|
"int": cg.int32,
|
||||||
"float": cg.float_,
|
"float": cg.float_,
|
||||||
|
"string": cg.std_string,
|
||||||
|
}
|
||||||
|
SERVICE_ARG_NATIVE_TYPES: dict[str, MockObj] = {
|
||||||
|
# Scalars are passed by value; string uses a non-owning view into rx_buf_.
|
||||||
|
**_SERVICE_ARG_SCALAR_TYPES,
|
||||||
"string": cg.StringRef,
|
"string": cg.StringRef,
|
||||||
"bool[]": cg.FixedVector.template(cg.bool_).operator("const").operator("ref"),
|
# Arrays are passed as non-owning const references into rx_buf_.
|
||||||
"int[]": cg.FixedVector.template(cg.int32).operator("const").operator("ref"),
|
**{
|
||||||
"float[]": cg.FixedVector.template(cg.float_).operator("const").operator("ref"),
|
f"{name}[]": cg.FixedVector.template(t).operator("const").operator("ref")
|
||||||
"string[]": cg.FixedVector.template(cg.std_string)
|
for name, t in _SERVICE_ARG_SCALAR_TYPES.items()
|
||||||
.operator("const")
|
},
|
||||||
.operator("ref"),
|
}
|
||||||
|
# Owning fallback types used when the action chain contains non-synchronous actions
|
||||||
|
# (delay, wait_until, script.wait, etc.). The default non-owning types reference
|
||||||
|
# storage in the receive buffer, which is reused once the synchronous portion of
|
||||||
|
# the chain returns. FixedVector is also non-copyable, so the deferred lambda
|
||||||
|
# capture in DelayAction::play_complex would fail to compile.
|
||||||
|
SERVICE_ARG_FALLBACK_TYPES: dict[str, MockObj] = {
|
||||||
|
"string": cg.std_string,
|
||||||
|
**{
|
||||||
|
f"{name}[]": cg.std_vector.template(t)
|
||||||
|
for name, t in _SERVICE_ARG_SCALAR_TYPES.items()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
CONF_ENCRYPTION = "encryption"
|
CONF_ENCRYPTION = "encryption"
|
||||||
CONF_BATCH_DELAY = "batch_delay"
|
CONF_BATCH_DELAY = "batch_delay"
|
||||||
@@ -382,17 +400,20 @@ async def to_code(config: ConfigType) -> None:
|
|||||||
func_args.append((cg.bool_, "return_response"))
|
func_args.append((cg.bool_, "return_response"))
|
||||||
|
|
||||||
# Check if action chain has non-synchronous actions that would make
|
# Check if action chain has non-synchronous actions that would make
|
||||||
# non-owning StringRef dangle (rx_buf_ reused after delay)
|
# non-owning args (StringRef, const FixedVector&) dangle once the
|
||||||
|
# rx_buf_ is reused after a delay/wait_until/script.wait/etc. The
|
||||||
|
# FixedVector references would also fail to compile because they
|
||||||
|
# are non-copyable and DelayAction captures args by value.
|
||||||
has_non_synchronous = automation.has_non_synchronous_actions(
|
has_non_synchronous = automation.has_non_synchronous_actions(
|
||||||
conf.get(CONF_THEN, [])
|
conf.get(CONF_THEN, [])
|
||||||
)
|
)
|
||||||
|
|
||||||
service_arg_names: list[str] = []
|
service_arg_names: list[str] = []
|
||||||
for name, var_ in conf[CONF_VARIABLES].items():
|
for name, var_ in conf[CONF_VARIABLES].items():
|
||||||
native = SERVICE_ARG_NATIVE_TYPES[var_]
|
if has_non_synchronous and var_ in SERVICE_ARG_FALLBACK_TYPES:
|
||||||
# Fall back to std::string for string args if non-synchronous actions exist
|
native = SERVICE_ARG_FALLBACK_TYPES[var_]
|
||||||
if has_non_synchronous and native is cg.StringRef:
|
else:
|
||||||
native = cg.std_string
|
native = SERVICE_ARG_NATIVE_TYPES[var_]
|
||||||
service_template_args.append(native)
|
service_template_args.append(native)
|
||||||
func_args.append((native, name))
|
func_args.append((native, name))
|
||||||
service_arg_names.append(name)
|
service_arg_names.append(name)
|
||||||
|
|||||||
@@ -91,6 +91,24 @@ api:
|
|||||||
- float_arr.size()
|
- float_arr.size()
|
||||||
- string_arr[0].c_str()
|
- string_arr[0].c_str()
|
||||||
- string_arr.size()
|
- string_arr.size()
|
||||||
|
# Test array + string args used after a non-synchronous action (delay).
|
||||||
|
# The default non-owning types (StringRef, const FixedVector&) would
|
||||||
|
# dangle once rx_buf_ is reused, and FixedVector is non-copyable so
|
||||||
|
# DelayAction's lambda capture would fail to compile. The api codegen
|
||||||
|
# must fall back to owning std::string / std::vector here.
|
||||||
|
- action: array_with_delay
|
||||||
|
variables:
|
||||||
|
name: string
|
||||||
|
int_arr: int[]
|
||||||
|
string_arr: string[]
|
||||||
|
then:
|
||||||
|
- delay: 20ms
|
||||||
|
- logger.log:
|
||||||
|
format: "Delayed: %s (%u ints, %u strings)"
|
||||||
|
args:
|
||||||
|
- name.c_str()
|
||||||
|
- int_arr.size()
|
||||||
|
- string_arr.size()
|
||||||
# Test ContinuationAction (IfAction with then/else branches)
|
# Test ContinuationAction (IfAction with then/else branches)
|
||||||
- action: test_if_action
|
- action: test_if_action
|
||||||
variables:
|
variables:
|
||||||
|
|||||||
Reference in New Issue
Block a user