1 #pragma once
2 
3 #include "types.hpp"
4 #include "utils.hpp"
5 
6 #include <sdbusplus/bus.hpp>
7 
8 #include <memory>
9 #include <utility>
10 
11 namespace phosphor
12 {
13 namespace inventory
14 {
15 namespace manager
16 {
17 
18 class Manager;
19 
20 /** @brief make_action
21  *
22  *  Adapt an action function object.
23  *
24  *  @param[in] action - The action being adapted.
25  *  @returns - The adapted action.
26  *
27  *  @tparam T - The type of the action being adapted.
28  */
29 template <typename T>
make_action(T && action)30 auto make_action(T&& action)
31 {
32     return Action(std::forward<T>(action));
33 }
34 
35 /** @brief make_filter
36  *
37  *  Adapt a filter function object.
38  *
39  *  @param[in] filter - The filter being adapted.
40  *  @returns - The adapted filter.
41  *
42  *  @tparam T - The type of the filter being adapted.
43  */
44 template <typename T>
make_filter(T && filter)45 auto make_filter(T&& filter)
46 {
47     return Filter(std::forward<T>(filter));
48 }
49 
50 /** @brief make_path_condition
51  *
52  *  Adapt a path_condition function object.
53  *
54  *  @param[in] filter - The functor being adapted.
55  *  @returns - The adapted functor.
56  *
57  *  @tparam T - The type of the functor being adapted.
58  */
59 template <typename T>
make_path_condition(T && condition)60 auto make_path_condition(T&& condition)
61 {
62     return PathCondition(std::forward<T>(condition));
63 }
64 
65 /** @brief make_get_property
66  *
67  *  Adapt a get_property function object.
68  *
69  *  @param[in] method - The functor being adapted.
70  *  @returns - The adapted functor.
71  *
72  *  @tparam T - The return type of the function object.
73  *  @tparam U - The type of the functor being adapted.
74  */
75 template <typename T, typename U>
make_get_property(U && method)76 auto make_get_property(U&& method)
77 {
78     return GetProperty<T>(std::forward<U>(method));
79 }
80 
81 template <typename T, typename... Args>
callArrayWithStatus(T && container,Args &&...args)82 auto callArrayWithStatus(T&& container, Args&&... args)
83 {
84     for (auto f : container)
85     {
86         if (!f(std::forward<Args>(args)...))
87         {
88             return false;
89         }
90     }
91     return true;
92 }
93 
94 namespace functor
95 {
96 
97 /** @brief Destroy objects action.  */
destroyObjects(std::vector<const char * > && paths,std::vector<PathCondition> && conditions)98 inline auto destroyObjects(std::vector<const char*>&& paths,
99                            std::vector<PathCondition>&& conditions)
100 {
101     return [=](auto& b, auto& m) {
102         for (const auto& p : paths)
103         {
104             if (callArrayWithStatus(conditions, p, b, m))
105             {
106                 m.destroyObjects({p});
107             }
108         }
109     };
110 }
111 
112 /** @brief Create objects action.  */
113 inline auto
createObjects(std::map<sdbusplus::message::object_path,Object> && objs)114     createObjects(std::map<sdbusplus::message::object_path, Object>&& objs)
115 {
116     return [=](auto&, auto& m) { m.createObjects(objs); };
117 }
118 
119 /** @brief Set a property action.
120  *
121  *  Invoke the requested method with a reference to the requested
122  *  sdbusplus server binding interface as a parameter.
123  *
124  *  @tparam T - The sdbusplus server binding interface type.
125  *  @tparam U - The type of the sdbusplus server binding member
126  *      function that sets the property.
127  *  @tparam V - The property value type.
128  *
129  *  @param[in] paths - The DBus paths on which the property should
130  *      be set.
131  *  @param[in] iface - The DBus interface hosting the property.
132  *  @param[in] member - Pointer to sdbusplus server binding member.
133  *  @param[in] value - The value the property should be set to.
134  *
135  *  @returns - A function object that sets the requested property
136  *      to the requested value.
137  */
138 template <typename T, typename U, typename V>
setProperty(std::vector<const char * > && paths,std::vector<PathCondition> && conditions,const char * iface,U && member,V && value)139 auto setProperty(std::vector<const char*>&& paths,
140                  std::vector<PathCondition>&& conditions, const char* iface,
141                  U&& member, V&& value)
142 {
143     // The manager is the only parameter passed to actions.
144     // Bind the path, interface, interface member function pointer,
145     // and value to a lambda.  When it is called, forward the
146     // path, interface and value on to the manager member function.
147     return [paths, conditions = conditions, iface, member,
148             value = std::forward<V>(value)](auto& b, auto& m) {
149         for (auto p : paths)
150         {
151             if (callArrayWithStatus(conditions, p, b, m))
152             {
153                 m.template invokeMethod<T>(p, iface, member, value);
154             }
155         }
156     };
157 }
158 
159 /** @brief Get a property.
160  *
161  *  Invoke the requested method with a reference to the requested
162  *  sdbusplus server binding interface as a parameter.
163  *
164  *  @tparam T - The sdbusplus server binding interface type.
165  *  @tparam U - The type of the sdbusplus server binding member
166  *      function that sets the property.
167  *
168  *  @param[in] path - The DBus path to get the property from.
169  *  @param[in] iface - The DBus interface hosting the property.
170  *  @param[in] member - Pointer to sdbusplus server binding member.
171  *  @param[in] prop - The property name to get the value from.
172  *
173  *  @returns - A function object that gets the requested property.
174  */
175 template <typename T, typename U>
getProperty(const char * path,const char * iface,U && member,const char * prop)176 inline auto getProperty(const char* path, const char* iface, U&& member,
177                         const char* prop)
178 {
179     return [path, iface, member, prop](auto& mgr) {
180         return mgr.template invokeMethod<T>(path, iface, member, prop);
181     };
182 }
183 
184 /** @struct PropertyChangedCondition
185  *  @brief Match filter functor that tests a property value.
186  *
187  *  @tparam T - The type of the property being tested.
188  *  @tparam U - The type of the condition checking functor.
189  */
190 template <typename T, typename U>
191 struct PropertyChangedCondition
192 {
193     PropertyChangedCondition() = delete;
194     ~PropertyChangedCondition() = default;
195     PropertyChangedCondition(const PropertyChangedCondition&) = default;
196     PropertyChangedCondition&
197         operator=(const PropertyChangedCondition&) = default;
198     PropertyChangedCondition(PropertyChangedCondition&&) = default;
199     PropertyChangedCondition& operator=(PropertyChangedCondition&&) = default;
PropertyChangedConditionphosphor::inventory::manager::functor::PropertyChangedCondition200     PropertyChangedCondition(const char* iface, const char* property,
201                              U&& condition) :
202         _iface(iface), _property(property),
203         _condition(std::forward<U>(condition))
204     {}
205 
206     /** @brief Test a property value.
207      *
208      * Extract the property from the PropertiesChanged
209      * message and run the condition test.
210      */
operator ()phosphor::inventory::manager::functor::PropertyChangedCondition211     bool operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
212                     Manager&) const
213     {
214         std::map<std::string, std::variant<T>> properties;
215         const char* iface = nullptr;
216 
217         msg.read(iface);
218         if (!iface || strcmp(iface, _iface))
219         {
220             return false;
221         }
222 
223         msg.read(properties);
224         auto it = properties.find(_property);
225         if (it == properties.cend())
226         {
227             return false;
228         }
229 
230         return _condition(std::forward<T>(std::get<T>(it->second)));
231     }
232 
233   private:
234     const char* _iface;
235     const char* _property;
236     U _condition;
237 };
238 
239 /** @struct PropertyConditionBase
240  *  @brief Match filter functor that tests a property value.
241  *
242  *  Base class for PropertyCondition - factored out code that
243  *  doesn't need to be templated.
244  */
245 struct PropertyConditionBase
246 {
247     PropertyConditionBase() = delete;
248     virtual ~PropertyConditionBase() = default;
249     PropertyConditionBase(const PropertyConditionBase&) = default;
250     PropertyConditionBase& operator=(const PropertyConditionBase&) = default;
251     PropertyConditionBase(PropertyConditionBase&&) = default;
252     PropertyConditionBase& operator=(PropertyConditionBase&&) = default;
253 
254     /** @brief Constructor
255      *
256      *  The service argument can be nullptr.  If something
257      *  else is provided the function will call the the
258      *  service directly.  If omitted, the function will
259      *  look up the service in the ObjectMapper.
260      *
261      *  @param path - The path of the object containing
262      *     the property to be tested.
263      *  @param iface - The interface hosting the property
264      *     to be tested.
265      *  @param property - The property to be tested.
266      *  @param service - The DBus service hosting the object.
267      */
PropertyConditionBasephosphor::inventory::manager::functor::PropertyConditionBase268     PropertyConditionBase(const char* path, const char* iface,
269                           const char* property, const char* service) :
270         _path(path ? path : std::string()), _iface(iface), _property(property),
271         _service(service)
272     {}
273 
274     /** @brief Forward comparison to type specific implementation. */
275     virtual bool eval(sdbusplus::message_t&) const = 0;
276 
277     /** @brief Forward comparison to type specific implementation. */
278     virtual bool eval(Manager&) const = 0;
279 
280     /** @brief Test a property value.
281      *
282      * Make a DBus call and test the value of any property.
283      */
284     bool operator()(sdbusplus::bus_t&, sdbusplus::message_t&, Manager&) const;
285 
286     /** @brief Test a property value.
287      *
288      * Make a DBus call and test the value of any property.
289      */
290     bool operator()(const std::string&, sdbusplus::bus_t&, Manager&) const;
291 
292   private:
293     std::string _path;
294     std::string _iface;
295     std::string _property;
296     const char* _service;
297 };
298 
299 /** @struct PropertyCondition
300  *  @brief Match filter functor that tests a property value.
301  *
302  *  @tparam T - The type of the property being tested.
303  *  @tparam U - The type of the condition checking functor.
304  *  @tparam V - The getProperty functor return type.
305  */
306 template <typename T, typename U, typename V>
307 struct PropertyCondition final : public PropertyConditionBase
308 {
309     PropertyCondition() = delete;
310     ~PropertyCondition() = default;
311     PropertyCondition(const PropertyCondition&) = default;
312     PropertyCondition& operator=(const PropertyCondition&) = default;
313     PropertyCondition(PropertyCondition&&) = default;
314     PropertyCondition& operator=(PropertyCondition&&) = default;
315 
316     /** @brief Constructor
317      *
318      *  The service & getProperty arguments can be nullptrs.
319      *  If something else is provided the function will call the the
320      *  service directly.  If omitted, the function will
321      *  look up the service in the ObjectMapper.
322      *  The getProperty function will be called to retrieve a property
323      *  value when given and the property is hosted by inventory manager.
324      *  When not given, the condition will default to return that the
325      *  condition failed and will not be executed.
326      *
327      *  @param path - The path of the object containing
328      *     the property to be tested.
329      *  @param iface - The interface hosting the property
330      *     to be tested.
331      *  @param property - The property to be tested.
332      *  @param condition - The test to run on the property.
333      *  @param service - The DBus service hosting the object.
334      *  @param getProperty - The function to get a property value
335      *     for the condition.
336      */
PropertyConditionphosphor::inventory::manager::functor::PropertyCondition337     PropertyCondition(const char* path, const char* iface, const char* property,
338                       U&& condition, const char* service,
339                       GetProperty<V>&& getProperty = nullptr) :
340         PropertyConditionBase(path, iface, property, service),
341         _condition(std::forward<decltype(condition)>(condition)),
342         _getProperty(getProperty)
343     {}
344 
345     /** @brief Test a property value.
346      *
347      * Make a DBus call and test the value of any property.
348      */
evalphosphor::inventory::manager::functor::PropertyCondition349     bool eval(sdbusplus::message_t& msg) const override
350     {
351         std::variant<T> value;
352         msg.read(value);
353         return _condition(std::forward<T>(std::get<T>(value)));
354     }
355 
356     /** @brief Retrieve a property value from inventory and test it.
357      *
358      *  Get a property from the inventory manager and test the value.
359      *  Default to fail the test where no function is given to get the
360      *  property from the inventory manager.
361      */
evalphosphor::inventory::manager::functor::PropertyCondition362     bool eval(Manager& mgr) const override
363     {
364         if (_getProperty)
365         {
366             auto variant = _getProperty(mgr);
367             auto value = std::get<T>(variant);
368             return _condition(std::forward<T>(value));
369         }
370         return false;
371     }
372 
373   private:
374     U _condition;
375     GetProperty<V> _getProperty;
376 };
377 
378 /** @brief Implicit type deduction for constructing PropertyChangedCondition. */
379 template <typename T>
propertyChangedTo(const char * iface,const char * property,T && val)380 auto propertyChangedTo(const char* iface, const char* property, T&& val)
381 {
382     auto condition = [val = std::forward<T>(val)](T&& arg) {
383         return arg == val;
384     };
385     using U = decltype(condition);
386     return PropertyChangedCondition<T, U>(iface, property,
387                                           std::move(condition));
388 }
389 
390 /** @brief Implicit type deduction for constructing PropertyCondition.  */
391 template <typename T, typename V = InterfaceVariantType>
propertyIs(const char * path,const char * iface,const char * property,T && val,const char * service=nullptr,GetProperty<V> && getProperty=nullptr)392 auto propertyIs(const char* path, const char* iface, const char* property,
393                 T&& val, const char* service = nullptr,
394                 GetProperty<V>&& getProperty = nullptr)
395 {
396     auto condition = [val = std::forward<T>(val)](T&& arg) {
397         return arg == val;
398     };
399     using U = decltype(condition);
400     return PropertyCondition<T, U, V>(path, iface, property,
401                                       std::move(condition), service,
402                                       std::move(getProperty));
403 }
404 } // namespace functor
405 } // namespace manager
406 } // namespace inventory
407 } // namespace phosphor
408 
409 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
410