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             {
133                 return false;
134             }
135 
136             msg.read(properties);
137             auto it = properties.find(_property);
138             if (it == properties.cend())
139             {
140                 return false;
141             }
142 
143             return _condition(it->second.template get<T>());
144         }
145 
146     private:
147         const char* _iface;
148         const char* _property;
149         U _condition;
150 };
151 
152 } // namespace property_condition
153 } // namespace details
154 
155 /** @brief The default filter.  */
156 inline bool none(sdbusplus::message::message&, Manager&) noexcept
157 {
158     return true;
159 }
160 
161 /** @brief Implicit type deduction for constructing PropertyCondition.  */
162 template <typename T>
163 auto propertyChangedTo(
164     const char* iface,
165     const char* property,
166     T val)
167 {
168     auto condition = [val = std::move(val)](const std::string & arg)
169     {
170         return arg == val;
171     };
172     using U = decltype(condition);
173     return details::property_condition::PropertyCondition<T, U>(
174                iface, property, std::move(condition));
175 }
176 
177 } // namespace filters
178 } // namespace manager
179 } // namespace inventory
180 } // namespace phosphor
181 
182 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
183