diff --git a/esphome/components/text_sensor/filter.cpp b/esphome/components/text_sensor/filter.cpp index 4cace372ae..4ee12e8602 100644 --- a/esphome/components/text_sensor/filter.cpp +++ b/esphome/components/text_sensor/filter.cpp @@ -9,19 +9,18 @@ namespace text_sensor { static const char *const TAG = "text_sensor.filter"; // Filter -void Filter::input(const std::string &value) { +void Filter::input(std::string value) { ESP_LOGVV(TAG, "Filter(%p)::input(%s)", this, value.c_str()); - optional out = this->new_value(value); - if (out.has_value()) - this->output(*out); + if (this->new_value(value)) + this->output(value); } -void Filter::output(const std::string &value) { +void Filter::output(std::string &value) { if (this->next_ == nullptr) { ESP_LOGVV(TAG, "Filter(%p)::output(%s) -> SENSOR", this, value.c_str()); this->parent_->internal_send_state_to_frontend(value); } else { ESP_LOGVV(TAG, "Filter(%p)::output(%s) -> %p", this, value.c_str(), this->next_); - this->next_->input(value); + this->next_->input(std::move(value)); } } void Filter::initialize(TextSensor *parent, Filter *next) { @@ -35,43 +34,48 @@ LambdaFilter::LambdaFilter(lambda_filter_t lambda_filter) : lambda_filter_(std:: const lambda_filter_t &LambdaFilter::get_lambda_filter() const { return this->lambda_filter_; } void LambdaFilter::set_lambda_filter(const lambda_filter_t &lambda_filter) { this->lambda_filter_ = lambda_filter; } -optional LambdaFilter::new_value(std::string value) { - auto it = this->lambda_filter_(value); - ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> %s", this, value.c_str(), it.value_or("").c_str()); - return it; +bool LambdaFilter::new_value(std::string &value) { + auto result = this->lambda_filter_(value); + if (result.has_value()) { + ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> %s (continue)", this, value.c_str(), result->c_str()); + value = std::move(*result); + return true; + } + ESP_LOGVV(TAG, "LambdaFilter(%p)::new_value(%s) -> (stop)", this, value.c_str()); + return false; } // ToUpperFilter -optional ToUpperFilter::new_value(std::string value) { +bool ToUpperFilter::new_value(std::string &value) { for (char &c : value) c = ::toupper(c); - return value; + return true; } // ToLowerFilter -optional ToLowerFilter::new_value(std::string value) { +bool ToLowerFilter::new_value(std::string &value) { for (char &c : value) c = ::tolower(c); - return value; + return true; } // Append -optional AppendFilter::new_value(std::string value) { +bool AppendFilter::new_value(std::string &value) { value.append(this->suffix_); - return value; + return true; } // Prepend -optional PrependFilter::new_value(std::string value) { +bool PrependFilter::new_value(std::string &value) { value.insert(0, this->prefix_); - return value; + return true; } // Substitute SubstituteFilter::SubstituteFilter(const std::initializer_list &substitutions) : substitutions_(substitutions) {} -optional SubstituteFilter::new_value(std::string value) { +bool SubstituteFilter::new_value(std::string &value) { for (const auto &sub : this->substitutions_) { // Compute lengths once per substitution (strlen is fast, called infrequently) const size_t from_len = strlen(sub.from); @@ -84,20 +88,20 @@ optional SubstituteFilter::new_value(std::string value) { pos += to_len; } } - return value; + return true; } // Map MapFilter::MapFilter(const std::initializer_list &mappings) : mappings_(mappings) {} -optional MapFilter::new_value(std::string value) { +bool MapFilter::new_value(std::string &value) { for (const auto &mapping : this->mappings_) { if (value == mapping.from) { value.assign(mapping.to); - return value; + return true; } } - return value; // Pass through if no match + return true; // Pass through if no match } } // namespace text_sensor diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index 0f66b753b4..1922b503ca 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -17,21 +17,20 @@ class Filter { public: /** This will be called every time the filter receives a new value. * - * It can return an empty optional to indicate that the filter chain - * should stop, otherwise the value in the filter will be passed down - * the chain. + * Modify the value in place. Return false to stop the filter chain + * (value will not be published), or true to continue. * - * @param value The new value. - * @return An optional string, the new value that should be pushed out. + * @param value The value to filter (modified in place). + * @return True to continue the filter chain, false to stop. */ - virtual optional new_value(std::string value) = 0; + virtual bool new_value(std::string &value) = 0; /// Initialize this filter, please note this can be called more than once. virtual void initialize(TextSensor *parent, Filter *next); - void input(const std::string &value); + void input(std::string value); - void output(const std::string &value); + void output(std::string &value); protected: friend TextSensor; @@ -45,15 +44,14 @@ using lambda_filter_t = std::function(std::string)>; /** This class allows for creation of simple template filters. * * The constructor accepts a lambda of the form std::string -> optional. - * It will be called with each new value in the filter chain and returns the modified - * value that shall be passed down the filter chain. Returning an empty Optional - * means that the value shall be discarded. + * Return a modified string to continue the chain, or return {} to stop + * (value will not be published). */ class LambdaFilter : public Filter { public: explicit LambdaFilter(lambda_filter_t lambda_filter); - optional new_value(std::string value) override; + bool new_value(std::string &value) override; const lambda_filter_t &get_lambda_filter() const; void set_lambda_filter(const lambda_filter_t &lambda_filter); @@ -71,7 +69,14 @@ class StatelessLambdaFilter : public Filter { public: explicit StatelessLambdaFilter(optional (*lambda_filter)(std::string)) : lambda_filter_(lambda_filter) {} - optional new_value(std::string value) override { return this->lambda_filter_(value); } + bool new_value(std::string &value) override { + auto result = this->lambda_filter_(value); + if (result.has_value()) { + value = std::move(*result); + return true; + } + return false; + } protected: optional (*lambda_filter_)(std::string); @@ -80,20 +85,20 @@ class StatelessLambdaFilter : public Filter { /// A simple filter that converts all text to uppercase class ToUpperFilter : public Filter { public: - optional new_value(std::string value) override; + bool new_value(std::string &value) override; }; /// A simple filter that converts all text to lowercase class ToLowerFilter : public Filter { public: - optional new_value(std::string value) override; + bool new_value(std::string &value) override; }; /// A simple filter that adds a string to the end of another string class AppendFilter : public Filter { public: explicit AppendFilter(const char *suffix) : suffix_(suffix) {} - optional new_value(std::string value) override; + bool new_value(std::string &value) override; protected: const char *suffix_; @@ -103,7 +108,7 @@ class AppendFilter : public Filter { class PrependFilter : public Filter { public: explicit PrependFilter(const char *prefix) : prefix_(prefix) {} - optional new_value(std::string value) override; + bool new_value(std::string &value) override; protected: const char *prefix_; @@ -118,7 +123,7 @@ struct Substitution { class SubstituteFilter : public Filter { public: explicit SubstituteFilter(const std::initializer_list &substitutions); - optional new_value(std::string value) override; + bool new_value(std::string &value) override; protected: FixedVector substitutions_; @@ -151,7 +156,7 @@ class SubstituteFilter : public Filter { class MapFilter : public Filter { public: explicit MapFilter(const std::initializer_list &mappings); - optional new_value(std::string value) override; + bool new_value(std::string &value) override; protected: FixedVector mappings_;