diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 1323cbd183b..f7189ad1346 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -522,8 +522,8 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c effects_list.init(light_effects.size() + 1); effects_list.push_back("None"); for (auto *effect : light_effects) { - // data() is safe as effect names are null-terminated strings from codegen - effects_list.push_back(effect->get_name().data()); + // c_str() is safe as effect names are null-terminated strings from codegen + effects_list.push_back(effect->get_name().c_str()); } } msg.effects = &effects_list; diff --git a/esphome/components/e131/e131.cpp b/esphome/components/e131/e131.cpp index c45651bf538..f11e7f4fe3a 100644 --- a/esphome/components/e131/e131.cpp +++ b/esphome/components/e131/e131.cpp @@ -83,7 +83,7 @@ void E131Component::add_effect(E131AddressableLightEffect *light_effect) { } auto effect_name = light_effect->get_name(); - ESP_LOGD(TAG, "Registering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.data(), + ESP_LOGD(TAG, "Registering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.c_str(), light_effect->get_first_universe(), light_effect->get_last_universe()); light_effects_.push_back(light_effect); @@ -100,7 +100,7 @@ void E131Component::remove_effect(E131AddressableLightEffect *light_effect) { } auto effect_name = light_effect->get_name(); - ESP_LOGD(TAG, "Unregistering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.data(), + ESP_LOGD(TAG, "Unregistering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.c_str(), light_effect->get_first_universe(), light_effect->get_last_universe()); // Swap with last element and pop for O(1) removal (order doesn't matter) diff --git a/esphome/components/e131/e131_addressable_light_effect.cpp b/esphome/components/e131/e131_addressable_light_effect.cpp index bfea6e6906a..7d62f739a24 100644 --- a/esphome/components/e131/e131_addressable_light_effect.cpp +++ b/esphome/components/e131/e131_addressable_light_effect.cpp @@ -60,7 +60,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet auto effect_name = get_name(); ESP_LOGV(TAG, "Applying data for '%.*s' on %d universe, for %" PRId32 "-%d.", (int) effect_name.size(), - effect_name.data(), universe, output_offset, output_end); + effect_name.c_str(), universe, output_offset, output_end); switch (channels_) { case E131_MONO: diff --git a/esphome/components/light/light_call.cpp b/esphome/components/light/light_call.cpp index de2f7a171a9..234d641f0dd 100644 --- a/esphome/components/light/light_call.cpp +++ b/esphome/components/light/light_call.cpp @@ -1,5 +1,4 @@ #include -#include #include "light_call.h" #include "light_state.h" @@ -155,15 +154,15 @@ void LightCall::perform() { } else if (this->has_effect_()) { // EFFECT - std::string_view effect_s; + StringRef effect_s; if (this->effect_ == 0u) { - effect_s = "None"; + effect_s = StringRef::from_lit("None"); } else { effect_s = this->parent_->effects_[this->effect_ - 1]->get_name(); } if (publish) { - ESP_LOGD(TAG, " Effect: '%.*s'", (int) effect_s.size(), effect_s.data()); + ESP_LOGD(TAG, " Effect: '%.*s'", (int) effect_s.size(), effect_s.c_str()); } this->parent_->start_effect_(this->effect_); @@ -513,9 +512,9 @@ LightCall &LightCall::set_effect(const char *effect, size_t len) { } bool found = false; - std::string_view effect_sv(effect, len); + StringRef effect_ref(effect, len); for (uint32_t i = 0; i < this->parent_->effects_.size(); i++) { - if (str_equals_case_insensitive(effect_sv, this->parent_->effects_[i]->get_name())) { + if (str_equals_case_insensitive(effect_ref, this->parent_->effects_[i]->get_name())) { this->set_effect(i + 1); found = true; break; diff --git a/esphome/components/light/light_effect.h b/esphome/components/light/light_effect.h index 9a09c6d63ea..a89e3fec5a9 100644 --- a/esphome/components/light/light_effect.h +++ b/esphome/components/light/light_effect.h @@ -1,8 +1,7 @@ #pragma once -#include - #include "esphome/core/component.h" +#include "esphome/core/string_ref.h" namespace esphome::light { @@ -27,7 +26,7 @@ class LightEffect { * Returns the name of this effect. * The underlying data is valid for the lifetime of the program (static string from codegen). */ - std::string_view get_name() const { return this->name_; } + StringRef get_name() const { return StringRef(this->name_); } /// Internal method called by the LightState when this light effect is registered in it. virtual void init() {} diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index c6f337dc759..91bb2e2f1f9 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -162,21 +162,12 @@ void LightState::publish_state() { LightOutput *LightState::get_output() const { return this->output_; } -static constexpr const char *EFFECT_NONE = "None"; static constexpr auto EFFECT_NONE_REF = StringRef::from_lit("None"); -std::string_view LightState::get_effect_name() { +StringRef LightState::get_effect_name() { if (this->active_effect_index_ > 0) { return this->effects_[this->active_effect_index_ - 1]->get_name(); } - return EFFECT_NONE; -} - -StringRef LightState::get_effect_name_ref() { - if (this->active_effect_index_ > 0) { - auto name = this->effects_[this->active_effect_index_ - 1]->get_name(); - return StringRef(name.data(), name.size()); - } return EFFECT_NONE_REF; } diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index b5840594cdc..83b9226d039 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -1,7 +1,5 @@ #pragma once -#include - #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/optional.h" @@ -142,9 +140,7 @@ class LightState : public EntityBase, public Component { LightOutput *get_output() const; /// Return the name of the current effect, or if no effect is active "None". - std::string_view get_effect_name(); - /// Return the name of the current effect as StringRef (for API usage) - StringRef get_effect_name_ref(); + StringRef get_effect_name(); /** Add a listener for remote values changes. * Listener is notified when the light's remote values change (state, brightness, color, etc.) diff --git a/esphome/components/mqtt/mqtt_light.cpp b/esphome/components/mqtt/mqtt_light.cpp index d126fe3012a..fac19f32109 100644 --- a/esphome/components/mqtt/mqtt_light.cpp +++ b/esphome/components/mqtt/mqtt_light.cpp @@ -81,8 +81,8 @@ void MQTTJSONLightComponent::send_discovery(JsonObject root, mqtt::SendDiscovery root[ESPHOME_F("effect")] = true; JsonArray effect_list = root[MQTT_EFFECT_LIST].to(); for (auto *effect : this->state_->get_effects()) { - // data() is safe as effect names are null-terminated strings from codegen - effect_list.add(effect->get_name().data()); + // c_str() is safe as effect names are null-terminated strings from codegen + effect_list.add(effect->get_name().c_str()); } effect_list.add(ESPHOME_F("None")); } diff --git a/esphome/components/prometheus/prometheus_handler.cpp b/esphome/components/prometheus/prometheus_handler.cpp index 79727b828c6..4f23f18942b 100644 --- a/esphome/components/prometheus/prometheus_handler.cpp +++ b/esphome/components/prometheus/prometheus_handler.cpp @@ -363,15 +363,14 @@ void PrometheusHandler::light_row_(AsyncResponseStream *stream, light::LightStat // Skip effect metrics if light has no effects if (!obj->get_effects().empty()) { // Effect - std::string_view effect = obj->get_effect_name(); + StringRef effect = obj->get_effect_name(); print_metric_labels_(stream, ESPHOME_F("esphome_light_effect_active"), obj, area, node, friendly_name); stream->print(ESPHOME_F("\",effect=\"")); // Only vary based on effect if (effect == "None") { stream->print(ESPHOME_F("None\"} 0\n")); } else { - // data() is safe as effect names are null-terminated strings from codegen - stream->print(effect.data()); + stream->write(effect.c_str(), effect.size()); stream->print(ESPHOME_F("\"} 1\n")); } } diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 1a0692a3865..309407fbec8 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -162,8 +162,8 @@ float random_float() { return static_cast(random_uint32()) / static_cast< bool str_equals_case_insensitive(const std::string &a, const std::string &b) { return strcasecmp(a.c_str(), b.c_str()) == 0; } -bool str_equals_case_insensitive(std::string_view a, std::string_view b) { - return a.size() == b.size() && strncasecmp(a.data(), b.data(), a.size()) == 0; +bool str_equals_case_insensitive(StringRef a, StringRef b) { + return a.size() == b.size() && strncasecmp(a.c_str(), b.c_str(), a.size()) == 0; } #if __cplusplus >= 202002L bool str_startswith(const std::string &str, const std::string &start) { return str.starts_with(start); } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 20b490fb279..a8a91dbda61 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -511,8 +511,8 @@ template constexpr T convert_little_endian(T val) { /// Compare strings for equality in case-insensitive manner. bool str_equals_case_insensitive(const std::string &a, const std::string &b); -/// Compare string_views for equality in case-insensitive manner. -bool str_equals_case_insensitive(std::string_view a, std::string_view b); +/// Compare StringRefs for equality in case-insensitive manner. +bool str_equals_case_insensitive(StringRef a, StringRef b); /// Check whether a string starts with a value. bool str_startswith(const std::string &str, const std::string &start); diff --git a/tests/components/light/common.yaml b/tests/components/light/common.yaml index 06243439b50..55525fc67ff 100644 --- a/tests/components/light/common.yaml +++ b/tests/components/light/common.yaml @@ -1,13 +1,13 @@ esphome: on_boot: then: - # Test LightEffect::get_name() returns string_view + # Test LightEffect::get_name() returns StringRef - lambda: |- - // Test LightEffect::get_name() returns std::string_view + // Test LightEffect::get_name() returns StringRef auto &effects = id(test_monochromatic_light).get_effects(); if (!effects.empty()) { - // Test: get_name() returns string_view - std::string_view name = effects[0]->get_name(); + // Test: get_name() returns StringRef + StringRef name = effects[0]->get_name(); // Test: comparison with string literal works directly if (name == "Strobe") { @@ -15,23 +15,23 @@ esphome: } // Test: safe logging with %.*s format - ESP_LOGI("test", "Effect name: %.*s", (int) name.size(), name.data()); + ESP_LOGI("test", "Effect name: %.*s", (int) name.size(), name.c_str()); - // Test: .data() for functions expecting const char* - ESP_LOGI("test", "Effect: %s", name.data()); + // Test: .c_str() for functions expecting const char* + ESP_LOGI("test", "Effect: %s", name.c_str()); // Test: explicit conversion to std::string - std::string name_str(name); + std::string name_str(name.c_str(), name.size()); ESP_LOGI("test", "As string: %s", name_str.c_str()); // Test: size() method ESP_LOGI("test", "Name length: %d", (int) name.size()); } - # Test LightState::get_effect_name() returns string_view + # Test LightState::get_effect_name() returns StringRef - lambda: |- - // Test LightState::get_effect_name() returns std::string_view - std::string_view current_effect = id(test_monochromatic_light).get_effect_name(); + // Test LightState::get_effect_name() returns StringRef + StringRef current_effect = id(test_monochromatic_light).get_effect_name(); // Test: comparison with "None" works directly if (current_effect == "None") { @@ -39,23 +39,23 @@ esphome: } // Test: safe logging - ESP_LOGI("test", "Current effect: %.*s", (int) current_effect.size(), current_effect.data()); + ESP_LOGI("test", "Current effect: %.*s", (int) current_effect.size(), current_effect.c_str()); - # Test str_equals_case_insensitive with string_view + # Test str_equals_case_insensitive with StringRef - lambda: |- - // Test str_equals_case_insensitive(string_view, string_view) + // Test str_equals_case_insensitive(StringRef, StringRef) auto &effects = id(test_monochromatic_light).get_effects(); if (!effects.empty()) { - std::string_view name = effects[0]->get_name(); + StringRef name = effects[0]->get_name(); // Test: case-insensitive comparison if (str_equals_case_insensitive(name, "STROBE")) { ESP_LOGI("test", "Case-insensitive match works"); } - // Test: case-insensitive with string_view from string + // Test: case-insensitive with StringRef from string std::string search = "strobe"; - if (str_equals_case_insensitive(std::string_view(search), name)) { + if (str_equals_case_insensitive(StringRef(search.c_str(), search.size()), name)) { ESP_LOGI("test", "Reverse comparison works"); } }