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::bus::bus&, sdbusplus::message::message&, Manager& >;
20 using FilterBasePtr = std::shared_ptr<FilterBase>;
21 template <typename T>
22 using Filter = holder::CallableHolder <
23                T, bool, sdbusplus::bus::bus&, 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()(
125             sdbusplus::bus::bus&,
126             sdbusplus::message::message& msg,
127             Manager&) const
128         {
129             std::map <
130             std::string,
131                 sdbusplus::message::variant<T >> properties;
132             const char* iface = nullptr;
133 
134             msg.read(iface);
135             if (!iface || strcmp(iface, _iface))
136             {
137                 return false;
138             }
139 
140             msg.read(properties);
141             auto it = properties.find(_property);
142             if (it == properties.cend())
143             {
144                 return false;
145             }
146 
147             return _condition(
148                        std::forward<T>(it->second.template get<T>()));
149         }
150 
151     private:
152         const char* _iface;
153         const char* _property;
154         U _condition;
155 };
156 
157 } // namespace property_condition
158 } // namespace details
159 
160 /** @brief Implicit type deduction for constructing PropertyChangedCondition.  */
161 template <typename T>
162 auto propertyChangedTo(
163     const char* iface,
164     const char* property,
165     T&& val)
166 {
167     auto condition = [val = std::move(val)](T && arg)
168     {
169         return arg == val;
170     };
171     using U = decltype(condition);
172     return details::property_condition::PropertyChangedCondition<T, U>(
173                iface, property, std::move(condition));
174 }
175 
176 } // namespace filters
177 } // namespace manager
178 } // namespace inventory
179 } // namespace phosphor
180 
181 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
182