mirror of
https://github.com/esphome/esphome.git
synced 2026-09-22 04:28:43 +00:00
Fix compat: use owned vector instead of leak, wire preset modes in subclasses
- Deprecated FanTraits setters store in an owned compat_preset_modes_ vector (same copy cost as pre-PR). No heap leak, no dangling pointer. - Subclass get_traits() calls wire_preset_modes_() to attach the Fan-owned pointer to the returned traits. - Getter/find/supports all check compat vector as fallback.
This commit is contained in:
@@ -15,8 +15,14 @@ static const char *const TAG = "fan";
|
||||
static const std::vector<const char *> EMPTY_PRESET_MODES; // NOLINT
|
||||
|
||||
const std::vector<const char *> &FanTraits::supported_preset_modes() const {
|
||||
// Compat: return empty ref when pointer is null. Remove in 2026.11.0 (change return to const vector *).
|
||||
return this->preset_modes_ ? *this->preset_modes_ : EMPTY_PRESET_MODES;
|
||||
if (this->preset_modes_) {
|
||||
return *this->preset_modes_;
|
||||
}
|
||||
// Compat: fall back to owned vector from deprecated setters. Remove in 2026.11.0 (change return to const vector *).
|
||||
if (!this->compat_preset_modes_.empty()) {
|
||||
return this->compat_preset_modes_;
|
||||
}
|
||||
return EMPTY_PRESET_MODES;
|
||||
}
|
||||
|
||||
// Fan direction strings indexed by FanDirection enum (0-1): FORWARD, REVERSE, plus UNKNOWN
|
||||
|
||||
@@ -175,6 +175,13 @@ class Fan : public EntityBase {
|
||||
const char *find_preset_mode_(const char *preset_mode);
|
||||
const char *find_preset_mode_(const char *preset_mode, size_t len);
|
||||
|
||||
/// Wire the Fan-owned preset modes pointer into the given traits object.
|
||||
void wire_preset_modes_(FanTraits &traits) {
|
||||
if (this->supported_preset_modes_) {
|
||||
traits.set_supported_preset_modes(this->supported_preset_modes_);
|
||||
}
|
||||
}
|
||||
|
||||
LazyCallbackManager<void()> state_callback_{};
|
||||
ESPPreferenceObject rtc_;
|
||||
FanRestoreMode restore_mode_;
|
||||
|
||||
@@ -39,31 +39,32 @@ class FanTraits {
|
||||
// Remove before 2026.11.0
|
||||
ESPDEPRECATED("Call set_supported_preset_modes() on the Fan entity instead. Removed in 2026.11.0", "2026.5.0")
|
||||
void set_supported_preset_modes(std::initializer_list<const char *> preset_modes) {
|
||||
// NOLINT - intentional leak: pointer must survive copies of FanTraits
|
||||
this->preset_modes_ = new std::vector<const char *>(preset_modes); // NOLINT
|
||||
// Compat: store in owned vector. Copies copy the vector (same cost as before this PR).
|
||||
this->compat_preset_modes_ = preset_modes;
|
||||
}
|
||||
// Remove before 2026.11.0
|
||||
ESPDEPRECATED("Call set_supported_preset_modes() on the Fan entity instead. Removed in 2026.11.0", "2026.5.0")
|
||||
void set_supported_preset_modes(const std::vector<const char *> &preset_modes) {
|
||||
this->preset_modes_ = new std::vector<const char *>(preset_modes); // NOLINT
|
||||
this->compat_preset_modes_ = preset_modes;
|
||||
}
|
||||
|
||||
/// Return if preset modes are supported
|
||||
bool supports_preset_modes() const { return this->preset_modes_ && !this->preset_modes_->empty(); }
|
||||
bool supports_preset_modes() const {
|
||||
return (this->preset_modes_ && !this->preset_modes_->empty()) || !this->compat_preset_modes_.empty();
|
||||
}
|
||||
/// Find and return the matching preset mode pointer from supported modes, or nullptr if not found.
|
||||
const char *find_preset_mode(const char *preset_mode) const {
|
||||
return this->find_preset_mode(preset_mode, preset_mode ? strlen(preset_mode) : 0);
|
||||
}
|
||||
const char *find_preset_mode(const char *preset_mode, size_t len) const {
|
||||
if (preset_mode == nullptr || len == 0)
|
||||
return nullptr;
|
||||
if (!this->preset_modes_) {
|
||||
if (preset_mode == nullptr || len == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto &modes = *this->preset_modes_;
|
||||
// Check pointer-based storage (new path) then compat owned vector (deprecated path)
|
||||
const auto &modes = this->preset_modes_ ? *this->preset_modes_ : this->compat_preset_modes_;
|
||||
for (const char *mode : modes) {
|
||||
if (strncmp(mode, preset_mode, len) == 0 && mode[len] == '\0') {
|
||||
return mode; // Return pointer from traits
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -75,6 +76,9 @@ class FanTraits {
|
||||
bool direction_{false};
|
||||
int speed_count_{};
|
||||
const std::vector<const char *> *preset_modes_{nullptr};
|
||||
// Compat: owned storage for deprecated setters. Copies copy the vector (same cost as pre-PR).
|
||||
// Remove in 2026.11.0.
|
||||
std::vector<const char *> compat_preset_modes_;
|
||||
};
|
||||
|
||||
} // namespace fan
|
||||
|
||||
@@ -24,7 +24,10 @@ class HBridgeFan : public Component, public fan::Fan {
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
fan::FanTraits get_traits() override { return this->traits_; }
|
||||
fan::FanTraits get_traits() override {
|
||||
this->wire_preset_modes_(this->traits_);
|
||||
return this->traits_;
|
||||
}
|
||||
|
||||
fan::FanCall brake();
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ class SpeedFan : public Component, public fan::Fan {
|
||||
void set_oscillating(output::BinaryOutput *oscillating) { this->oscillating_ = oscillating; }
|
||||
void set_direction(output::BinaryOutput *direction) { this->direction_ = direction; }
|
||||
void set_preset_modes(std::initializer_list<const char *> presets) { this->set_supported_preset_modes(presets); }
|
||||
fan::FanTraits get_traits() override { return this->traits_; }
|
||||
fan::FanTraits get_traits() override {
|
||||
this->wire_preset_modes_(this->traits_);
|
||||
return this->traits_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void control(const fan::FanCall &call) override;
|
||||
|
||||
@@ -14,7 +14,10 @@ class TemplateFan final : public Component, public fan::Fan {
|
||||
void set_has_oscillating(bool has_oscillating) { this->has_oscillating_ = has_oscillating; }
|
||||
void set_speed_count(int count) { this->speed_count_ = count; }
|
||||
void set_preset_modes(std::initializer_list<const char *> presets) { this->set_supported_preset_modes(presets); }
|
||||
fan::FanTraits get_traits() override { return this->traits_; }
|
||||
fan::FanTraits get_traits() override {
|
||||
this->wire_preset_modes_(this->traits_);
|
||||
return this->traits_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void control(const fan::FanCall &call) override;
|
||||
|
||||
Reference in New Issue
Block a user