1
#pragma once
2

            
3
#include <string>
4

            
5
#include "envoy/matcher/matcher.h"
6

            
7
namespace Envoy {
8
namespace Matcher {
9

            
10
/**
11
 * Implementation of a map matcher which performs matches against the data provided by DataType.
12
 */
13
template <class DataType>
14
class MapMatcher : public MatchTree<DataType>, Logger::Loggable<Logger::Id::matcher> {
15
public:
16
  // Adds a child to the map.
17
  virtual void addChild(std::string value, OnMatch<DataType>&& on_match) PURE;
18

            
19
65
  ActionMatchResult doNoMatch(const DataType& data, SkippedMatchCb skipped_match_cb) {
20
65
    if (data_input_->get(data).availability() == DataAvailability::MoreDataMightBeAvailable) {
21
3
      return ActionMatchResult::insufficientData();
22
3
    }
23
62
    return MatchTree<DataType>::handleRecursionAndSkips(on_no_match_, data, skipped_match_cb);
24
65
  }
25

            
26
  ActionMatchResult match(const DataType& data,
27
386
                          SkippedMatchCb skipped_match_cb = nullptr) override {
28
386
    const auto input = data_input_->get(data);
29
386
    if (input.availability() == DataAvailability::NotAvailable) {
30
11
      return ActionMatchResult::insufficientData();
31
11
    }
32

            
33
    // Returns `on_no_match` when input data is empty. (i.e., is absl::monostate).
34
375
    auto string_data = input.stringData();
35
375
    if (!string_data) {
36
57
      return MatchTree<DataType>::handleRecursionAndSkips(on_no_match_, data, skipped_match_cb);
37
57
    }
38

            
39
    // This is safe to pass string_data because input remains alive.
40
318
    return doMatch(data, *string_data, skipped_match_cb);
41
375
  }
42

            
43
  template <class DataType2, class ActionFactoryContext> friend class MatchTreeFactory;
44
  MapMatcher(DataInputPtr<DataType>&& data_input, absl::optional<OnMatch<DataType>> on_no_match,
45
             absl::Status& creation_status)
46
378
      : data_input_(std::move(data_input)), on_no_match_(std::move(on_no_match)) {
47
378
    auto input_type = data_input_->dataInputType();
48
378
    if (input_type != DefaultMatchingDataType) {
49
2
      creation_status = absl::InvalidArgumentError(
50
2
          absl::StrCat("Unsupported data input type: ", input_type,
51
2
                       ", currently only string type is supported in map matcher"));
52
2
    }
53
378
  }
54

            
55
  const DataInputPtr<DataType> data_input_;
56
  const absl::optional<OnMatch<DataType>> on_no_match_;
57

            
58
  // The inner match method. Attempts to match against the resulting data string.
59
  // If a match is found, handleRecursionAndSkips must be called on it.
60
  // Otherwise ActionMatchResult::noMatch() or ActionMatchResult::insufficientData() should be
61
  // returned.
62
  virtual ActionMatchResult doMatch(const DataType& data, absl::string_view key,
63
                                    SkippedMatchCb skipped_match_cb) PURE;
64
};
65

            
66
} // namespace Matcher
67
} // namespace Envoy