• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include "pw_assert/check.h"
17 #include "pw_containers/intrusive_list.h"
18 #include "pw_containers/vector.h"
19 #include "pw_metric/metric.h"
20 #include "pw_status/status.h"
21 #include "pw_tokenizer/tokenize.h"
22 
23 namespace pw::metric::internal {
24 
25 class MetricWriter {
26  public:
27   virtual ~MetricWriter() = default;
28   virtual Status Write(const Metric& metric, const Vector<Token>& path) = 0;
29 };
30 
31 // Walk a metric tree recursively; passing metrics with their path (names) to a
32 // MetricWriter that can consume them.
33 class MetricWalker {
34  public:
MetricWalker(MetricWriter & writer)35   MetricWalker(MetricWriter& writer) : writer_(writer) {}
36 
Walk(const IntrusiveList<Metric> & metrics)37   Status Walk(const IntrusiveList<Metric>& metrics) {
38     for (const auto& m : metrics) {
39       ScopedName scoped_name(m.name(), *this);
40       PW_TRY(writer_.Write(m, path_));
41     }
42     return OkStatus();
43   }
44 
Walk(const IntrusiveList<Group> & groups)45   Status Walk(const IntrusiveList<Group>& groups) {
46     for (const auto& g : groups) {
47       PW_TRY(Walk(g));
48     }
49     return OkStatus();
50   }
51 
Walk(const Group & group)52   Status Walk(const Group& group) {
53     ScopedName scoped_name(group.name(), *this);
54     PW_TRY(Walk(group.children()));
55     PW_TRY(Walk(group.metrics()));
56     return OkStatus();
57   }
58 
59  private:
60   // Exists to safely push/pop parent groups from the explicit stack.
61   struct ScopedName {
ScopedNameScopedName62     ScopedName(Token name, MetricWalker& rhs) : walker(rhs) {
63       // Metrics are too deep; bump path_ capacity.
64       PW_ASSERT(walker.path_.size() < walker.path_.capacity());
65       walker.path_.push_back(name);
66     }
~ScopedNameScopedName67     ~ScopedName() { walker.path_.pop_back(); }
68     MetricWalker& walker;
69   };
70 
71   Vector<Token, /*capacity=*/4> path_;
72   MetricWriter& writer_;
73 };
74 
75 }  // namespace pw::metric::internal
76