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*, std::vector<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, const std::vector<FilterBasePtr>& filters) :
69         Event(Type::DBUS_SIGNAL),
70         std::tuple<const char*, std::vector<FilterBasePtr>>(
71                     sig, std::move(filters)) {}
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 PropertyChangedCondition
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 PropertyChangedCondition
106 {
107         PropertyChangedCondition() = delete;
108         ~PropertyChangedCondition() = default;
109         PropertyChangedCondition(const PropertyChangedCondition&) = default;
110         PropertyChangedCondition& operator=(const PropertyChangedCondition&) = delete;
111         PropertyChangedCondition(PropertyChangedCondition&&) = default;
112         PropertyChangedCondition& operator=(PropertyChangedCondition&&) = default;
113         PropertyChangedCondition(const char* iface, const char* property,
114                                  U&& condition) :
115             _iface(iface),
116             _property(property),
117             _condition(std::forward<U>(condition)) { }
118 
119         /** @brief Test a property value.
120          *
121          * Extract the property from the PropertiesChanged
122          * message and run the condition test.
123          */
124         bool operator()(sdbusplus::message::message& msg, Manager&) const
125         {
126             std::map <
127             std::string,
128                 sdbusplus::message::variant<T >> properties;
129             const char* iface = nullptr;
130 
131             msg.read(iface);
132             if (!iface || strcmp(iface, _iface))
133             {
134                 return false;
135             }
136 
137             msg.read(properties);
138             auto it = properties.find(_property);
139             if (it == properties.cend())
140             {
141                 return false;
142             }
143 
144             return _condition(
145                        std::forward<T>(it->second.template get<T>()));
146         }
147 
148     private:
149         const char* _iface;
150         const char* _property;
151         U _condition;
152 };
153 
154 } // namespace property_condition
155 } // namespace details
156 
157 /** @brief Implicit type deduction for constructing PropertyChangedCondition.  */
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)](T && arg)
165     {
166         return arg == val;
167     };
168     using U = decltype(condition);
169     return details::property_condition::PropertyChangedCondition<T, U>(
170                iface, property, std::move(condition));
171 }
172 
173 } // namespace filters
174 } // namespace manager
175 } // namespace inventory
176 } // namespace phosphor
177 
178 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
179