mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
Keep get_name() returning a reference off ESP8266
ProgmemStringRef now holds a StringRef, so get_name() and friendly_name_() can keep returning const StringRef & on other platforms. External components that return get_name() from a const StringRef & getter would otherwise return a reference to a temporary. friendly_name_() is deprecated there, not removed.
This commit is contained in:
@@ -413,6 +413,9 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
|
||||
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
|
||||
|
||||
// Pull these properties from EntityBase if not overridden
|
||||
#ifndef USE_ESP8266
|
||||
const StringRef &MQTTComponent::friendly_name_() const { return this->get_entity()->get_name_progmem().ram_ref(); }
|
||||
#endif
|
||||
const LogString *MQTTComponent::log_name_() const { return this->get_entity()->get_log_name(); }
|
||||
StringRef MQTTComponent::get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
|
||||
return this->get_entity()->get_object_id_to(buf);
|
||||
|
||||
@@ -300,6 +300,10 @@ class MQTTComponent : public Component {
|
||||
|
||||
/// Entity name for a "%s" log argument.
|
||||
const LogString *log_name_() const;
|
||||
#ifndef USE_ESP8266
|
||||
ESPDEPRECATED("Use log_name_() for logging. Removed in 2027.5.0", "2026.11.0")
|
||||
const StringRef &friendly_name_() const;
|
||||
#endif
|
||||
|
||||
/// Get the icon field of this component into a stack buffer
|
||||
const char *get_icon_to_(std::span<char, MAX_ICON_LENGTH> buf) const { return this->get_entity()->get_icon_to(buf); }
|
||||
|
||||
@@ -86,8 +86,8 @@ class EntityBase {
|
||||
}
|
||||
#else
|
||||
ESPDEPRECATED("Use get_name_to() or get_log_name() instead. Will be removed in ESPHome 2027.5.0", "2026.11.0")
|
||||
StringRef get_name() const { return this->name_.ram_ref(); }
|
||||
StringRef get_name_to(std::span<char, ENTITY_NAME_BUF_SIZE> /*buffer*/) const { return this->name_.ram_ref(); }
|
||||
const StringRef &get_name() const { return this->name_.ram_ref(); }
|
||||
const StringRef &get_name_to(std::span<char, ENTITY_NAME_BUF_SIZE> /*buffer*/) const { return this->name_.ram_ref(); }
|
||||
#endif
|
||||
|
||||
bool name_equals(const StringRef &other) const { return this->name_.equals(other); }
|
||||
|
||||
+14
-14
@@ -223,27 +223,28 @@ inline std::string operator+(const std::string &lhs, const StringRef &rhs) {
|
||||
str.append(rhs.c_str(), rhs.size());
|
||||
return str;
|
||||
}
|
||||
|
||||
/// A string that may live in flash (on ESP8266): pointer and length, with no byte-reading operations.
|
||||
/// progmem_ptr() is safe as a "%s" log argument; read the contents with write_to() or equals().
|
||||
class ProgmemStringRef {
|
||||
public:
|
||||
constexpr ProgmemStringRef() = default;
|
||||
constexpr ProgmemStringRef(const char *s, size_t len) : base_(s), len_(len) {}
|
||||
constexpr explicit ProgmemStringRef(const StringRef &s) : base_(s.c_str()), len_(s.size()) {}
|
||||
constexpr ProgmemStringRef(const char *s, size_t len) : ref_(s, len) {}
|
||||
constexpr explicit ProgmemStringRef(const StringRef &s) : ref_(s) {}
|
||||
|
||||
constexpr const char *progmem_ptr() const { return this->base_; }
|
||||
constexpr size_t size() const { return this->len_; }
|
||||
constexpr bool empty() const { return this->len_ == 0; }
|
||||
constexpr const char *progmem_ptr() const { return this->ref_.c_str(); }
|
||||
constexpr size_t size() const { return this->ref_.size(); }
|
||||
constexpr bool empty() const { return this->ref_.empty(); }
|
||||
|
||||
/// Copy into buf (null terminated, truncated to fit), returns the length copied.
|
||||
size_t write_to(char *buf, size_t buf_size) const {
|
||||
if (buf_size == 0)
|
||||
return 0;
|
||||
size_t len = std::min(this->len_, buf_size - 1);
|
||||
size_t len = std::min(this->ref_.size(), buf_size - 1);
|
||||
#ifdef USE_ESP8266
|
||||
memcpy_P(buf, this->base_, len);
|
||||
memcpy_P(buf, this->ref_.c_str(), len);
|
||||
#else
|
||||
std::memcpy(buf, this->base_, len);
|
||||
std::memcpy(buf, this->ref_.c_str(), len);
|
||||
#endif
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
@@ -251,27 +252,26 @@ class ProgmemStringRef {
|
||||
|
||||
bool equals(const StringRef &other) const {
|
||||
#ifdef USE_ESP8266
|
||||
return other.size() == this->len_ && memcmp_P(other.c_str(), this->base_, this->len_) == 0;
|
||||
return other.size() == this->ref_.size() && memcmp_P(other.c_str(), this->ref_.c_str(), other.size()) == 0;
|
||||
#else
|
||||
return other == StringRef(this->base_, this->len_);
|
||||
return other == this->ref_;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef USE_ESP8266
|
||||
/// The string is in RAM here, so it can be viewed directly.
|
||||
constexpr StringRef ram_ref() const { return StringRef(this->base_, this->len_); }
|
||||
constexpr const StringRef &ram_ref() const { return this->ref_; }
|
||||
#endif
|
||||
|
||||
// Remove before 2027.5.0
|
||||
[[deprecated(
|
||||
"May point to flash; use progmem_ptr() or the owner's accessors. Removed in 2027.5.0")]] constexpr const char *
|
||||
c_str() const {
|
||||
return this->base_;
|
||||
return this->ref_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
const char *base_{""};
|
||||
size_t len_{0};
|
||||
StringRef ref_;
|
||||
};
|
||||
|
||||
// String conversion functions for ADL compatibility (allows stoi(x) where x is StringRef)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "esphome/core/entity_base.h"
|
||||
#include "esphome/core/string_ref.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace esphome::core::testing {
|
||||
|
||||
@@ -190,6 +193,13 @@ TEST(ProgmemStringRef, EqualsComparesLengthAndContent) {
|
||||
EXPECT_FALSE(ref.equals(StringRef("Bedroom")));
|
||||
}
|
||||
|
||||
// get_name() must keep returning a reference: external code returns it from `const StringRef &` getters
|
||||
static_assert(std::is_same_v<decltype(std::declval<const ProgmemStringRef &>().ram_ref()), const StringRef &>);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
static_assert(std::is_same_v<decltype(std::declval<const EntityBase &>().get_name()), const StringRef &>);
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
TEST(ProgmemStringRef, DefaultIsEmpty) {
|
||||
ProgmemStringRef ref;
|
||||
EXPECT_TRUE(ref.empty());
|
||||
|
||||
Reference in New Issue
Block a user