1 #pragma once
2 
3 #include <utility>
4 #include <memory>
5 #include <sdbusplus/message.hpp>
6 #include "utils.hpp"
7 
8 namespace phosphor
9 {
10 namespace inventory
11 {
12 namespace manager
13 {
14 
15 class Manager;
16 namespace details
17 {
18 using FilterBase = holder::CallableBase<
19     bool, sdbusplus::message::message&, Manager&>;
20 using FilterBasePtr = std::shared_ptr<FilterBase>;
21 template <typename T>
22 using Filter = holder::CallableHolder<
23     T, bool, sdbusplus::message::message&, Manager&>;
24 
25 /** @struct Event
26  *  @brief Event object interface.
27  */
28 struct Event
29 {
30     enum class Type
31     {
32         DBUS_SIGNAL,
33     };
34 
35     virtual ~Event() = default;
36     Event(const Event&) = default;
37     Event& operator=(const Event&) = default;
38     Event(Event&&) = default;
39     Event& operator=(Event&&) = default;
40     explicit Event(Type t) : type(t) {}
41 
42     Type type;
43 };
44 
45 using EventBasePtr = std::shared_ptr<Event>;
46 
47 /** @struct DbusSignal
48  *  @brief DBus signal event.
49  *
50  *  DBus signal events are an association of a match signature
51  *  and filtering function object.
52  */
53 struct DbusSignal final :
54     public Event,
55     public std::tuple<const char *, FilterBasePtr>
56 {
57     virtual ~DbusSignal() = default;
58     DbusSignal(const DbusSignal&) = default;
59     DbusSignal & operator=(const DbusSignal&) = delete;
60     DbusSignal(DbusSignal&&) = default;
61     DbusSignal& operator=(DbusSignal&&) = default;
62 
63     /** @brief Import from signature and filter constructor.
64      *
65      *  @param[in] sig - The DBus match signature.
66      *  @param[in] filter - A DBus signal match callback filtering function.
67      */
68     DbusSignal(const char *sig, FilterBasePtr filter) :
69         Event(Type::DBUS_SIGNAL),
70         std::tuple<const char *, FilterBasePtr>(
71                 sig, std::move(filter)) {}
72 };
73 
74 /** @brief make_filter
75  *
76  *  Adapt a filter function object.
77  *
78  *  @param[in] filter - The filter being adapted.
79  *  @returns - The adapted filter.
80  *
81  *  @tparam T - The type of the filter being adapted.
82  */
83 template <typename T>
84 auto make_filter(T&& filter)
85 {
86     return Filter<T>::template make_shared<Filter<T>>(
87         std::forward<T>(filter));
88 }
89 } // namespace details
90 
91 namespace filters
92 {
93 namespace details
94 {
95 namespace property_condition
96 {
97 
98 /** @struct PropertyCondition
99  *  @brief Match filter functor that tests a property value.
100  *
101  *  @tparam T - The type of the property being tested.
102  *  @tparam U - The type of the condition checking functor.
103  */
104 template <typename T, typename U>
105 struct PropertyCondition
106 {
107     PropertyCondition() = delete;
108     ~PropertyCondition() = default;
109     PropertyCondition(const PropertyCondition&) = default;
110     PropertyCondition & operator=(const PropertyCondition&) = delete;
111     PropertyCondition(PropertyCondition&&) = default;
112     PropertyCondition& operator=(PropertyCondition&&) = default;
113     PropertyCondition(const char *iface, const char *property, U &&condition) :
114         _iface(iface),
115         _property(property),
116         _condition(std::forward<U>(condition)) { }
117 
118     /** @brief Test a property value.
119      *
120      * Extract the property from the PropertiesChanged
121      * message and run the condition test.
122      */
123     bool operator()(sdbusplus::message::message &msg, Manager &) const
124     {
125         std::map<
126             std::string,
127             sdbusplus::message::variant<T>> properties;
128         const char *iface = nullptr;
129 
130         msg.read(iface);
131         if(strcmp(iface, _iface))
132                 return false;
133 
134         msg.read(properties);
135         auto it = properties.find(_property);
136         if(it == properties.cend())
137             return false;
138 
139         return _condition(it->second);
140     }
141 
142     private:
143     const char *_iface;
144     const char *_property;
145     U _condition;
146 };
147 
148 } // namespace property_condition
149 } // namespace details
150 
151 /** @brief The default filter.  */
152 inline bool none(sdbusplus::message::message &, Manager &) noexcept
153 {
154     return true;
155 }
156 
157 /** @brief Implicit type deduction for constructing PropertyCondition.  */
158 template <typename T>
159 auto propertyChangedTo(
160         const char *iface,
161         const char *property,
162         T val)
163 {
164     auto condition = [val = std::move(val)](auto arg){return arg == val;};
165     using U = decltype(condition);
166     return details::property_condition::PropertyCondition<T, U>(
167             iface, property, std::move(condition));
168 }
169 
170 } // namespace filters
171 } // namespace manager
172 } // namespace inventory
173 } // namespace phosphor
174 
175 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
176