mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	relo
This commit is contained in:
		| @@ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/cover/cover.h" | #include "esphome/components/cover/cover.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/time.h" | #include "esphome/core/time.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/time.h" | #include "esphome/core/time.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/time.h" | #include "esphome/core/time.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/lock/lock.h" | #include "esphome/components/lock/lock.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/sensor/sensor.h" | #include "esphome/components/sensor/sensor.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/switch/switch.h" | #include "esphome/components/switch/switch.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								esphome/components/template/template_lambda.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								esphome/components/template/template_lambda.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/optional.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  |  | ||||||
|  | /** Lightweight wrapper for template platform lambdas (stateless function pointers only). | ||||||
|  |  * | ||||||
|  |  * This optimizes template platforms by storing only a function pointer (4 bytes on ESP32) | ||||||
|  |  * instead of std::function (16-32 bytes). | ||||||
|  |  * | ||||||
|  |  * IMPORTANT: This only supports stateless lambdas (no captures). The set_template() method | ||||||
|  |  * is an internal API used by YAML codegen, not intended for external use. | ||||||
|  |  * | ||||||
|  |  * Lambdas must return optional<T> to support the pattern: | ||||||
|  |  *   return {};    // Don't publish a value | ||||||
|  |  *   return 42.0;  // Publish this value | ||||||
|  |  * | ||||||
|  |  * operator() returns optional<T>, returning nullopt when no lambda is set (nullptr check). | ||||||
|  |  * | ||||||
|  |  * @tparam T The return type (e.g., float for sensor values) | ||||||
|  |  * @tparam Args Optional arguments for the lambda | ||||||
|  |  */ | ||||||
|  | template<typename T, typename... Args> class TemplateLambda { | ||||||
|  |  public: | ||||||
|  |   TemplateLambda() : f_(nullptr) {} | ||||||
|  |  | ||||||
|  |   /** Set the lambda function pointer. | ||||||
|  |    * INTERNAL API: Only for use by YAML codegen. | ||||||
|  |    * Only stateless lambdas (no captures) are supported. | ||||||
|  |    */ | ||||||
|  |   void set(optional<T> (*f)(Args...)) { this->f_ = f; } | ||||||
|  |  | ||||||
|  |   /** Check if a lambda is set */ | ||||||
|  |   bool has_value() const { return this->f_ != nullptr; } | ||||||
|  |  | ||||||
|  |   /** Call the lambda, returning nullopt if no lambda is set */ | ||||||
|  |   optional<T> operator()(Args... args) { | ||||||
|  |     if (this->f_ == nullptr) | ||||||
|  |       return nullopt; | ||||||
|  |     return this->f_(args...); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Alias for operator() for compatibility */ | ||||||
|  |   optional<T> call(Args... args) { return (*this)(args...); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   optional<T> (*f_)(Args...);  // Function pointer (4 bytes on ESP32) | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace esphome | ||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/preferences.h" | #include "esphome/core/preferences.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace template_ { | namespace template_ { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/text_sensor/text_sensor.h" | #include "esphome/components/text_sensor/text_sensor.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/core/automation.h" | #include "esphome/core/automation.h" | ||||||
| #include "esphome/core/template_lambda.h" | #include "../template_lambda.h" | ||||||
| #include "esphome/components/valve/valve.h" | #include "esphome/components/valve/valve.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|   | |||||||
| @@ -1,120 +0,0 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <functional> |  | ||||||
| #include <concepts> |  | ||||||
| #include "esphome/core/optional.h" |  | ||||||
|  |  | ||||||
| namespace esphome { |  | ||||||
|  |  | ||||||
| /** Helper class for template platforms that stores either a stateless lambda (function pointer) |  | ||||||
|  * or a stateful lambda (std::function pointer). |  | ||||||
|  * |  | ||||||
|  * This provides backward compatibility with PR #11555 while maintaining the optimization: |  | ||||||
|  * - Stateless lambdas (no capture) → function pointer (4 bytes on ESP32) |  | ||||||
|  * - Stateful lambdas (with capture) → pointer to std::function (4 bytes on ESP32) |  | ||||||
|  * Total size: enum (1 byte) + union (4 bytes) + padding = 8 bytes (same as PR #11555) |  | ||||||
|  * |  | ||||||
|  * Both lambda types must return optional<T> (as YAML codegen does) to support the pattern: |  | ||||||
|  *   return {};  // Don't publish a value |  | ||||||
|  *   return 42.0;  // Publish this value |  | ||||||
|  * |  | ||||||
|  * operator() returns optional<T>, returning nullopt when no lambda is set (type == NONE). |  | ||||||
|  * This eliminates redundant "is lambda set" checks by reusing optional's discriminator. |  | ||||||
|  * |  | ||||||
|  * @tparam T The return type (e.g., float for TemplateLambda<optional<float>>) |  | ||||||
|  * @tparam Args Optional arguments for the lambda |  | ||||||
|  */ |  | ||||||
| template<typename T, typename... Args> class TemplateLambda { |  | ||||||
|  public: |  | ||||||
|   TemplateLambda() : type_(NONE) {} |  | ||||||
|  |  | ||||||
|   // For stateless lambdas: use function pointer |  | ||||||
|   template<typename F> |  | ||||||
|   requires std::invocable<F, Args...> && std::convertible_to < F, optional<T>(*) |  | ||||||
|   (Args...) > void set(F f) { |  | ||||||
|     this->reset_(); |  | ||||||
|     this->type_ = STATELESS_LAMBDA; |  | ||||||
|     this->stateless_f_ = f;  // Implicit conversion to function pointer |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // For stateful lambdas: use std::function pointer |  | ||||||
|   template<typename F> |  | ||||||
|   requires std::invocable<F, Args...> && |  | ||||||
|       (!std::convertible_to<F, optional<T> (*)(Args...)>) &&std::convertible_to<std::invoke_result_t<F, Args...>, |  | ||||||
|                                                                                 optional<T>> void set(F &&f) { |  | ||||||
|     this->reset_(); |  | ||||||
|     this->type_ = LAMBDA; |  | ||||||
|     this->f_ = new std::function<optional<T>(Args...)>(std::forward<F>(f)); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   ~TemplateLambda() { this->reset_(); } |  | ||||||
|  |  | ||||||
|   // Copy constructor |  | ||||||
|   TemplateLambda(const TemplateLambda &) = delete; |  | ||||||
|   TemplateLambda &operator=(const TemplateLambda &) = delete; |  | ||||||
|  |  | ||||||
|   // Move constructor |  | ||||||
|   TemplateLambda(TemplateLambda &&other) noexcept : type_(other.type_) { |  | ||||||
|     if (type_ == LAMBDA) { |  | ||||||
|       this->f_ = other.f_; |  | ||||||
|       other.f_ = nullptr; |  | ||||||
|     } else if (type_ == STATELESS_LAMBDA) { |  | ||||||
|       this->stateless_f_ = other.stateless_f_; |  | ||||||
|     } |  | ||||||
|     other.type_ = NONE; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   TemplateLambda &operator=(TemplateLambda &&other) noexcept { |  | ||||||
|     if (this != &other) { |  | ||||||
|       this->reset_(); |  | ||||||
|       this->type_ = other.type_; |  | ||||||
|       if (type_ == LAMBDA) { |  | ||||||
|         this->f_ = other.f_; |  | ||||||
|         other.f_ = nullptr; |  | ||||||
|       } else if (type_ == STATELESS_LAMBDA) { |  | ||||||
|         this->stateless_f_ = other.stateless_f_; |  | ||||||
|       } |  | ||||||
|       other.type_ = NONE; |  | ||||||
|     } |  | ||||||
|     return *this; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool has_value() const { return this->type_ != NONE; } |  | ||||||
|  |  | ||||||
|   // Returns optional<T>, returning nullopt if no lambda is set |  | ||||||
|   optional<T> operator()(Args... args) { |  | ||||||
|     switch (this->type_) { |  | ||||||
|       case STATELESS_LAMBDA: |  | ||||||
|         return this->stateless_f_(args...);  // Direct function pointer call |  | ||||||
|       case LAMBDA: |  | ||||||
|         return (*this->f_)(args...);  // std::function call via pointer |  | ||||||
|       case NONE: |  | ||||||
|       default: |  | ||||||
|         return nullopt;  // No lambda set |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   optional<T> call(Args... args) { return (*this)(args...); } |  | ||||||
|  |  | ||||||
|  protected: |  | ||||||
|   void reset_() { |  | ||||||
|     if (this->type_ == LAMBDA) { |  | ||||||
|       delete this->f_; |  | ||||||
|       this->f_ = nullptr; |  | ||||||
|     } |  | ||||||
|     this->type_ = NONE; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   enum : uint8_t { |  | ||||||
|     NONE, |  | ||||||
|     STATELESS_LAMBDA, |  | ||||||
|     LAMBDA, |  | ||||||
|   } type_; |  | ||||||
|  |  | ||||||
|   union { |  | ||||||
|     optional<T> (*stateless_f_)(Args...);     // Function pointer (4 bytes on ESP32) |  | ||||||
|     std::function<optional<T>(Args...)> *f_;  // Pointer to std::function (4 bytes on ESP32) |  | ||||||
|   }; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| }  // namespace esphome |  | ||||||
| @@ -10,26 +10,12 @@ esphome: | |||||||
|         state: !lambda "return 42.0;" |         state: !lambda "return 42.0;" | ||||||
|  |  | ||||||
|     # Test C++ API: set_template() with stateless lambda (no captures) |     # Test C++ API: set_template() with stateless lambda (no captures) | ||||||
|  |     # IMPORTANT: set_template() is an internal API. Only stateless lambdas are supported. | ||||||
|     - lambda: |- |     - lambda: |- | ||||||
|         id(template_sens).set_template([]() -> esphome::optional<float> { |         id(template_sens).set_template([]() -> esphome::optional<float> { | ||||||
|           return 123.0f; |           return 123.0f; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|     # Test C++ API: set_template() with stateful lambda (with captures) |  | ||||||
|     # This is the regression test for issue #11555 |  | ||||||
|     - lambda: |- |  | ||||||
|         float captured_value = 456.0f; |  | ||||||
|         id(template_sens).set_template([captured_value]() -> esphome::optional<float> { |  | ||||||
|           return captured_value; |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|     # Test C++ API: set_template() with more complex capture |  | ||||||
|     - lambda: |- |  | ||||||
|         auto sensor_id = id(template_sens); |  | ||||||
|         id(template_number).set_template([sensor_id]() -> esphome::optional<float> { |  | ||||||
|           return sensor_id->state * 2.0f; |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|     - datetime.date.set: |     - datetime.date.set: | ||||||
|         id: test_date |         id: test_date | ||||||
|         date: |         date: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user