blob: 903cbd0a216881ceb26f0d490437c0743ece4b1f [file] [log] [blame]
#pragma once
#include "types.hpp"
#include "utils.hpp"
#include <sdbusplus/bus.hpp>
#include <memory>
#include <utility>
namespace phosphor
{
namespace inventory
{
namespace manager
{
class Manager;
/** @brief make_action
*
* Adapt an action function object.
*
* @param[in] action - The action being adapted.
* @returns - The adapted action.
*
* @tparam T - The type of the action being adapted.
*/
template <typename T>
auto make_action(T&& action)
{
return Action(std::forward<T>(action));
}
/** @brief make_filter
*
* Adapt a filter function object.
*
* @param[in] filter - The filter being adapted.
* @returns - The adapted filter.
*
* @tparam T - The type of the filter being adapted.
*/
template <typename T>
auto make_filter(T&& filter)
{
return Filter(std::forward<T>(filter));
}
/** @brief make_path_condition
*
* Adapt a path_condition function object.
*
* @param[in] filter - The functor being adapted.
* @returns - The adapted functor.
*
* @tparam T - The type of the functor being adapted.
*/
template <typename T>
auto make_path_condition(T&& condition)
{
return PathCondition(std::forward<T>(condition));
}
/** @brief make_get_property
*
* Adapt a get_property function object.
*
* @param[in] method - The functor being adapted.
* @returns - The adapted functor.
*
* @tparam T - The return type of the function object.
* @tparam U - The type of the functor being adapted.
*/
template <typename T, typename U>
auto make_get_property(U&& method)
{
return GetProperty<T>(std::forward<U>(method));
}
template <typename T, typename... Args>
auto callArrayWithStatus(T&& container, Args&&... args)
{
for (auto f : container)
{
if (!f(std::forward<Args>(args)...))
{
return false;
}
}
return true;
}
namespace functor
{
/** @brief Destroy objects action. */
inline auto destroyObjects(std::vector<const char*>&& paths,
std::vector<PathCondition>&& conditions)
{
return [=](auto& b, auto& m) {
for (const auto& p : paths)
{
if (callArrayWithStatus(conditions, p, b, m))
{
m.destroyObjects({p});
}
}
};
}
/** @brief Create objects action. */
inline auto
createObjects(std::map<sdbusplus::message::object_path, Object>&& objs)
{
return [=](auto&, auto& m) { m.createObjects(objs); };
}
/** @brief Set a property action.
*
* Invoke the requested method with a reference to the requested
* sdbusplus server binding interface as a parameter.
*
* @tparam T - The sdbusplus server binding interface type.
* @tparam U - The type of the sdbusplus server binding member
* function that sets the property.
* @tparam V - The property value type.
*
* @param[in] paths - The DBus paths on which the property should
* be set.
* @param[in] iface - The DBus interface hosting the property.
* @param[in] member - Pointer to sdbusplus server binding member.
* @param[in] value - The value the property should be set to.
*
* @returns - A function object that sets the requested property
* to the requested value.
*/
template <typename T, typename U, typename V>
auto setProperty(std::vector<const char*>&& paths,
std::vector<PathCondition>&& conditions, const char* iface,
U&& member, V&& value)
{
// The manager is the only parameter passed to actions.
// Bind the path, interface, interface member function pointer,
// and value to a lambda. When it is called, forward the
// path, interface and value on to the manager member function.
return [paths, conditions = conditions, iface, member,
value = std::forward<V>(value)](auto& b, auto& m) {
for (auto p : paths)
{
if (callArrayWithStatus(conditions, p, b, m))
{
m.template invokeMethod<T>(p, iface, member, value);
}
}
};
}
/** @brief Get a property.
*
* Invoke the requested method with a reference to the requested
* sdbusplus server binding interface as a parameter.
*
* @tparam T - The sdbusplus server binding interface type.
* @tparam U - The type of the sdbusplus server binding member
* function that sets the property.
*
* @param[in] path - The DBus path to get the property from.
* @param[in] iface - The DBus interface hosting the property.
* @param[in] member - Pointer to sdbusplus server binding member.
* @param[in] prop - The property name to get the value from.
*
* @returns - A function object that gets the requested property.
*/
template <typename T, typename U>
inline auto getProperty(const char* path, const char* iface, U&& member,
const char* prop)
{
return [path, iface, member, prop](auto& mgr) {
return mgr.template invokeMethod<T>(path, iface, member, prop);
};
}
/** @struct PropertyChangedCondition
* @brief Match filter functor that tests a property value.
*
* @tparam T - The type of the property being tested.
* @tparam U - The type of the condition checking functor.
*/
template <typename T, typename U>
struct PropertyChangedCondition
{
PropertyChangedCondition() = delete;
~PropertyChangedCondition() = default;
PropertyChangedCondition(const PropertyChangedCondition&) = default;
PropertyChangedCondition&
operator=(const PropertyChangedCondition&) = default;
PropertyChangedCondition(PropertyChangedCondition&&) = default;
PropertyChangedCondition& operator=(PropertyChangedCondition&&) = default;
PropertyChangedCondition(const char* iface, const char* property,
U&& condition) :
_iface(iface),
_property(property), _condition(std::forward<U>(condition))
{}
/** @brief Test a property value.
*
* Extract the property from the PropertiesChanged
* message and run the condition test.
*/
bool operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
Manager&) const
{
std::map<std::string, std::variant<T>> properties;
const char* iface = nullptr;
msg.read(iface);
if (!iface || strcmp(iface, _iface))
{
return false;
}
msg.read(properties);
auto it = properties.find(_property);
if (it == properties.cend())
{
return false;
}
return _condition(std::forward<T>(std::get<T>(it->second)));
}
private:
const char* _iface;
const char* _property;
U _condition;
};
/** @struct PropertyConditionBase
* @brief Match filter functor that tests a property value.
*
* Base class for PropertyCondition - factored out code that
* doesn't need to be templated.
*/
struct PropertyConditionBase
{
PropertyConditionBase() = delete;
virtual ~PropertyConditionBase() = default;
PropertyConditionBase(const PropertyConditionBase&) = default;
PropertyConditionBase& operator=(const PropertyConditionBase&) = default;
PropertyConditionBase(PropertyConditionBase&&) = default;
PropertyConditionBase& operator=(PropertyConditionBase&&) = default;
/** @brief Constructor
*
* The service argument can be nullptr. If something
* else is provided the function will call the the
* service directly. If omitted, the function will
* look up the service in the ObjectMapper.
*
* @param path - The path of the object containing
* the property to be tested.
* @param iface - The interface hosting the property
* to be tested.
* @param property - The property to be tested.
* @param service - The DBus service hosting the object.
*/
PropertyConditionBase(const char* path, const char* iface,
const char* property, const char* service) :
_path(path ? path : std::string()),
_iface(iface), _property(property), _service(service)
{}
/** @brief Forward comparison to type specific implementation. */
virtual bool eval(sdbusplus::message_t&) const = 0;
/** @brief Forward comparison to type specific implementation. */
virtual bool eval(Manager&) const = 0;
/** @brief Test a property value.
*
* Make a DBus call and test the value of any property.
*/
bool operator()(sdbusplus::bus_t&, sdbusplus::message_t&, Manager&) const;
/** @brief Test a property value.
*
* Make a DBus call and test the value of any property.
*/
bool operator()(const std::string&, sdbusplus::bus_t&, Manager&) const;
private:
std::string _path;
std::string _iface;
std::string _property;
const char* _service;
};
/** @struct PropertyCondition
* @brief Match filter functor that tests a property value.
*
* @tparam T - The type of the property being tested.
* @tparam U - The type of the condition checking functor.
* @tparam V - The getProperty functor return type.
*/
template <typename T, typename U, typename V>
struct PropertyCondition final : public PropertyConditionBase
{
PropertyCondition() = delete;
~PropertyCondition() = default;
PropertyCondition(const PropertyCondition&) = default;
PropertyCondition& operator=(const PropertyCondition&) = default;
PropertyCondition(PropertyCondition&&) = default;
PropertyCondition& operator=(PropertyCondition&&) = default;
/** @brief Constructor
*
* The service & getProperty arguments can be nullptrs.
* If something else is provided the function will call the the
* service directly. If omitted, the function will
* look up the service in the ObjectMapper.
* The getProperty function will be called to retrieve a property
* value when given and the property is hosted by inventory manager.
* When not given, the condition will default to return that the
* condition failed and will not be executed.
*
* @param path - The path of the object containing
* the property to be tested.
* @param iface - The interface hosting the property
* to be tested.
* @param property - The property to be tested.
* @param condition - The test to run on the property.
* @param service - The DBus service hosting the object.
* @param getProperty - The function to get a property value
* for the condition.
*/
PropertyCondition(const char* path, const char* iface, const char* property,
U&& condition, const char* service,
GetProperty<V>&& getProperty = nullptr) :
PropertyConditionBase(path, iface, property, service),
_condition(std::forward<decltype(condition)>(condition)),
_getProperty(getProperty)
{}
/** @brief Test a property value.
*
* Make a DBus call and test the value of any property.
*/
bool eval(sdbusplus::message_t& msg) const override
{
std::variant<T> value;
msg.read(value);
return _condition(std::forward<T>(std::get<T>(value)));
}
/** @brief Retrieve a property value from inventory and test it.
*
* Get a property from the inventory manager and test the value.
* Default to fail the test where no function is given to get the
* property from the inventory manager.
*/
bool eval(Manager& mgr) const override
{
if (_getProperty)
{
auto variant = _getProperty(mgr);
auto value = std::get<T>(variant);
return _condition(std::forward<T>(value));
}
return false;
}
private:
U _condition;
GetProperty<V> _getProperty;
};
/** @brief Implicit type deduction for constructing PropertyChangedCondition. */
template <typename T>
auto propertyChangedTo(const char* iface, const char* property, T&& val)
{
auto condition = [val = std::forward<T>(val)](T&& arg) {
return arg == val;
};
using U = decltype(condition);
return PropertyChangedCondition<T, U>(iface, property,
std::move(condition));
}
/** @brief Implicit type deduction for constructing PropertyCondition. */
template <typename T, typename V = InterfaceVariantType>
auto propertyIs(const char* path, const char* iface, const char* property,
T&& val, const char* service = nullptr,
GetProperty<V>&& getProperty = nullptr)
{
auto condition = [val = std::forward<T>(val)](T&& arg) {
return arg == val;
};
using U = decltype(condition);
return PropertyCondition<T, U, V>(path, iface, property,
std::move(condition), service,
std::move(getProperty));
}
} // namespace functor
} // namespace manager
} // namespace inventory
} // namespace phosphor
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4