[scheduler] Use enum class for InternalSchedulerID to avoid materialized constant

The struct + constexpr namespace approach caused the compiler to
materialize POLLING_UPDATE as a 4-byte symbol. An enum class with
uint32_t underlying type gives the same type safety but enum values
are true compile-time constants that never get materialized.
This commit is contained in:
J. Nick Koston
2026-02-09 06:25:55 -06:00
parent d9f7c26b16
commit dd2c5838e1
4 changed files with 19 additions and 23 deletions

View File

@@ -192,15 +192,16 @@ template<typename... Ts> class DelayAction : public Action<Ts...>, public Compon
if constexpr (sizeof...(Ts) == 0) {
App.scheduler.set_timer_common_(
this, Scheduler::SchedulerItem::TIMEOUT, Scheduler::NameType::NUMERIC_ID_INTERNAL, nullptr,
scheduler_internal_id::DELAY_ACTION.id, this->delay_.value(), [this]() { this->play_next_(); },
static_cast<uint32_t>(InternalSchedulerID::DELAY_ACTION), this->delay_.value(),
[this]() { this->play_next_(); },
/* is_retry= */ false, /* skip_cancel= */ this->num_running_ > 1);
} else {
// For delays with arguments, use std::bind to preserve argument values
// Arguments must be copied because original references may be invalid after delay
auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
App.scheduler.set_timer_common_(this, Scheduler::SchedulerItem::TIMEOUT, Scheduler::NameType::NUMERIC_ID_INTERNAL,
nullptr, scheduler_internal_id::DELAY_ACTION.id, this->delay_.value(x...),
std::move(f),
nullptr, static_cast<uint32_t>(InternalSchedulerID::DELAY_ACTION),
this->delay_.value(x...), std::move(f),
/* is_retry= */ false, /* skip_cancel= */ this->num_running_ > 1);
}
}
@@ -209,7 +210,7 @@ template<typename... Ts> class DelayAction : public Action<Ts...>, public Compon
void play(const Ts &...x) override { /* ignore - see play_complex */
}
void stop() override { this->cancel_timeout(scheduler_internal_id::DELAY_ACTION); }
void stop() override { this->cancel_timeout(InternalSchedulerID::DELAY_ACTION); }
};
template<typename... Ts> class LambdaAction : public Action<Ts...> {

View File

@@ -528,12 +528,12 @@ void PollingComponent::call_setup() {
void PollingComponent::start_poller() {
// Register interval.
this->set_interval(scheduler_internal_id::POLLING_UPDATE, this->get_update_interval(), [this]() { this->update(); });
this->set_interval(InternalSchedulerID::POLLING_UPDATE, this->get_update_interval(), [this]() { this->update(); });
}
void PollingComponent::stop_poller() {
// Clear the interval to suspend component
this->cancel_interval(scheduler_internal_id::POLLING_UPDATE);
this->cancel_interval(InternalSchedulerID::POLLING_UPDATE);
}
uint32_t PollingComponent::get_update_interval() const { return this->update_interval_; }

View File

@@ -49,21 +49,14 @@ extern const float LATE;
static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
/// Type-safe wrapper for internal scheduler IDs used by core base classes.
/// Type-safe scheduler IDs for core base classes.
/// Uses a separate NameType (NUMERIC_ID_INTERNAL) so IDs can never collide
/// with component-level NUMERIC_ID values, even if the uint32_t values overlap.
struct InternalSchedulerID {
uint32_t id;
enum class InternalSchedulerID : uint32_t {
POLLING_UPDATE = 0, // PollingComponent interval
DELAY_ACTION = 1, // DelayAction timeout
};
/// Reserved scheduler IDs for core base classes.
/// These use InternalSchedulerID which routes through NUMERIC_ID_INTERNAL,
/// a separate matching namespace from the NUMERIC_ID used by components.
namespace scheduler_internal_id {
constexpr InternalSchedulerID POLLING_UPDATE{0}; // PollingComponent interval
constexpr InternalSchedulerID DELAY_ACTION{1}; // DelayAction timeout
} // namespace scheduler_internal_id
// Forward declaration
class PollingComponent;

View File

@@ -48,8 +48,8 @@ class Scheduler {
void set_timeout(Component *component, uint32_t id, uint32_t timeout, std::function<void()> func);
/// Set a timeout with an internal scheduler ID (separate namespace from component NUMERIC_ID)
void set_timeout(Component *component, InternalSchedulerID id, uint32_t timeout, std::function<void()> func) {
this->set_timer_common_(component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL, nullptr, id.id, timeout,
std::move(func));
this->set_timer_common_(component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL, nullptr,
static_cast<uint32_t>(id), timeout, std::move(func));
}
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
@@ -57,7 +57,8 @@ class Scheduler {
bool cancel_timeout(Component *component, const char *name);
bool cancel_timeout(Component *component, uint32_t id);
bool cancel_timeout(Component *component, InternalSchedulerID id) {
return this->cancel_item_(component, NameType::NUMERIC_ID_INTERNAL, nullptr, id.id, SchedulerItem::TIMEOUT);
return this->cancel_item_(component, NameType::NUMERIC_ID_INTERNAL, nullptr, static_cast<uint32_t>(id),
SchedulerItem::TIMEOUT);
}
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
@@ -76,8 +77,8 @@ class Scheduler {
void set_interval(Component *component, uint32_t id, uint32_t interval, std::function<void()> func);
/// Set an interval with an internal scheduler ID (separate namespace from component NUMERIC_ID)
void set_interval(Component *component, InternalSchedulerID id, uint32_t interval, std::function<void()> func) {
this->set_timer_common_(component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL, nullptr, id.id, interval,
std::move(func));
this->set_timer_common_(component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL, nullptr,
static_cast<uint32_t>(id), interval, std::move(func));
}
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
@@ -85,7 +86,8 @@ class Scheduler {
bool cancel_interval(Component *component, const char *name);
bool cancel_interval(Component *component, uint32_t id);
bool cancel_interval(Component *component, InternalSchedulerID id) {
return this->cancel_item_(component, NameType::NUMERIC_ID_INTERNAL, nullptr, id.id, SchedulerItem::INTERVAL);
return this->cancel_item_(component, NameType::NUMERIC_ID_INTERNAL, nullptr, static_cast<uint32_t>(id),
SchedulerItem::INTERVAL);
}
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")