mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 13:43:00 +00:00
[template] Use placement new for template text restore saver (#15883)
This commit is contained in:
@@ -3,6 +3,7 @@ import esphome.codegen as cg
|
|||||||
from esphome.components import text
|
from esphome.components import text
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
CONF_INITIAL_VALUE,
|
CONF_INITIAL_VALUE,
|
||||||
CONF_LAMBDA,
|
CONF_LAMBDA,
|
||||||
CONF_MAX_LENGTH,
|
CONF_MAX_LENGTH,
|
||||||
@@ -12,6 +13,7 @@ from esphome.const import (
|
|||||||
CONF_RESTORE_VALUE,
|
CONF_RESTORE_VALUE,
|
||||||
CONF_SET_ACTION,
|
CONF_SET_ACTION,
|
||||||
)
|
)
|
||||||
|
from esphome.core import ID
|
||||||
|
|
||||||
from .. import template_ns
|
from .. import template_ns
|
||||||
|
|
||||||
@@ -84,8 +86,15 @@ async def to_code(config):
|
|||||||
if initial_value_config := config.get(CONF_INITIAL_VALUE):
|
if initial_value_config := config.get(CONF_INITIAL_VALUE):
|
||||||
cg.add(var.set_initial_value(initial_value_config))
|
cg.add(var.set_initial_value(initial_value_config))
|
||||||
if config[CONF_RESTORE_VALUE]:
|
if config[CONF_RESTORE_VALUE]:
|
||||||
args = cg.TemplateArguments(config[CONF_MAX_LENGTH])
|
saver_id = ID(
|
||||||
saver = TextSaverTemplate.template(args).new()
|
f"{config[CONF_ID].id}_value_saver",
|
||||||
|
is_declaration=True,
|
||||||
|
type=TextSaverBase,
|
||||||
|
)
|
||||||
|
saver_type = TextSaverTemplate.template(
|
||||||
|
cg.TemplateArguments(config[CONF_MAX_LENGTH])
|
||||||
|
)
|
||||||
|
saver = cg.Pvariable(saver_id, saver_type.new())
|
||||||
cg.add(var.set_value_saver(saver))
|
cg.add(var.set_value_saver(saver))
|
||||||
|
|
||||||
if CONF_SET_ACTION in config:
|
if CONF_SET_ACTION in config:
|
||||||
|
|||||||
0
tests/component_tests/template/__init__.py
Normal file
0
tests/component_tests/template/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
esphome:
|
||||||
|
name: test
|
||||||
|
|
||||||
|
host:
|
||||||
|
|
||||||
|
text:
|
||||||
|
- platform: template
|
||||||
|
name: "Test Text Restore"
|
||||||
|
id: test_text_restore
|
||||||
|
optimistic: true
|
||||||
|
max_length: 10
|
||||||
|
mode: text
|
||||||
|
initial_value: "hello"
|
||||||
|
restore_value: true
|
||||||
44
tests/component_tests/template/test_template_text.py
Normal file
44
tests/component_tests/template/test_template_text.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""Tests for the template text component."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def test_template_text_saver_uses_placement_new_with_templated_subclass(
|
||||||
|
generate_main: Callable[[str | Path], str],
|
||||||
|
component_config_path: Callable[[str], Path],
|
||||||
|
) -> None:
|
||||||
|
"""Regression test for template text restore saver using placement new.
|
||||||
|
|
||||||
|
When ``restore_value: true``, the saver is its own Pvariable with
|
||||||
|
placement new: storage is sized for ``TextSaver<MAX_LENGTH>``, the
|
||||||
|
declared pointer stays at ``TemplateTextSaverBase *`` for polymorphism,
|
||||||
|
and the templated subclass constructor runs. A regression would either
|
||||||
|
reintroduce the heap ``new TextSaver<...>()`` expression or size the
|
||||||
|
storage for the base class and silently skip the subclass ctor.
|
||||||
|
"""
|
||||||
|
main_cpp = generate_main(component_config_path("template_text_restore.yaml"))
|
||||||
|
|
||||||
|
# Storage is sized and aligned for the templated subclass.
|
||||||
|
assert "sizeof(template_::TextSaver<10>)" in main_cpp
|
||||||
|
assert "alignas(template_::TextSaver<10>)" in main_cpp
|
||||||
|
# Pointer declared as base type for polymorphism.
|
||||||
|
assert (
|
||||||
|
"static template_::TemplateTextSaverBase *const test_text_restore_value_saver"
|
||||||
|
in main_cpp
|
||||||
|
)
|
||||||
|
# Placement new runs the templated subclass constructor.
|
||||||
|
assert "new(test_text_restore_value_saver) template_::TextSaver<10>()" in main_cpp
|
||||||
|
# Base-class default ctor must NOT be used.
|
||||||
|
assert (
|
||||||
|
"new(test_text_restore_value_saver) template_::TemplateTextSaverBase()"
|
||||||
|
not in main_cpp
|
||||||
|
)
|
||||||
|
# No heap `new TextSaver<...>()` left over — the pre-fix pattern.
|
||||||
|
assert "new template_::TextSaver<" not in main_cpp
|
||||||
|
# Saver is wired into the text component.
|
||||||
|
assert (
|
||||||
|
"test_text_restore->set_value_saver(test_text_restore_value_saver)" in main_cpp
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user