File parameter_client.hpp
File List > agnocast_wrapper > parameter_client.hpp
Go to the documentation of this file
// Copyright 2026 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "nebula_core_ros/agnocast_wrapper/node.hpp"
#include "nebula_core_ros/agnocast_wrapper/runtime.hpp"
#include <rclcpp/callback_group.hpp>
#include <rclcpp/parameter.hpp>
#include <rclcpp/parameter_client.hpp>
#include <rclcpp/qos.hpp>
#include <rclcpp/version.h>
#include <chrono>
#include <cstdint>
#include <functional>
#include <future>
#include <memory>
#include <ratio>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include <vector>
namespace nebula::agnocast_wrapper
{
namespace detail
{
inline const rclcpp::QoS & checked_parameters_qos(const rclcpp::QoS & qos)
{
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
throw std::invalid_argument(
"AsyncParametersClient: transient-local durability is not supported, use volatile instead");
}
if (qos.reliability() == rclcpp::ReliabilityPolicy::BestEffort) {
throw std::invalid_argument(
"AsyncParametersClient: best-effort reliability is not supported, use reliable instead");
}
return qos;
}
inline auto to_rclcpp_parameters_qos(const rclcpp::QoS & qos)
{
#if RCLCPP_VERSION_MAJOR >= 28
return qos;
#else
return qos.get_rmw_qos_profile();
#endif
}
} // namespace detail
} // namespace nebula::agnocast_wrapper
#ifdef USE_AGNOCAST_ENABLED
#include <agnocast/node/agnocast_parameter_client.hpp>
namespace nebula::agnocast_wrapper
{
class AsyncParametersClient
{
public:
explicit AsyncParametersClient(
nebula::agnocast_wrapper::Node * node, const std::string & remote_node_name = "",
const rclcpp::QoS & qos = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: impl_(
// A conditional, not an if/else: only the selected branch is evaluated, and the other
// one's accessor would throw.
use_agnocast()
? decltype(impl_)(
std::in_place_type<AgnocastImpl>, node->get_agnocast_node().get(), remote_node_name,
detail::checked_parameters_qos(qos), std::move(group))
: decltype(impl_)(
std::in_place_type<RclcppImpl>, node->get_rclcpp_node().get(), remote_node_name,
detail::to_rclcpp_parameters_qos(detail::checked_parameters_qos(qos)),
std::move(group)))
{
}
std::shared_future<std::vector<rclcpp::Parameter>> get_parameters(
const std::vector<std::string> & names,
std::function<void(std::shared_future<std::vector<rclcpp::Parameter>>)> callback = nullptr)
{
return std::visit(
[&](auto & impl) { return impl.get_parameters(names, std::move(callback)); }, impl_);
}
template <typename RepT = int64_t, typename RatioT = std::milli>
bool wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return std::visit([&](auto & impl) { return impl.wait_for_service(timeout); }, impl_);
}
bool service_is_ready() const
{
return std::visit([](const auto & impl) { return impl.service_is_ready(); }, impl_);
}
AsyncParametersClient(const AsyncParametersClient &) = delete;
AsyncParametersClient & operator=(const AsyncParametersClient &) = delete;
AsyncParametersClient(AsyncParametersClient &&) = delete;
AsyncParametersClient & operator=(AsyncParametersClient &&) = delete;
private:
using RclcppImpl = ::rclcpp::AsyncParametersClient;
using AgnocastImpl = ::agnocast::AsyncParametersClient;
std::variant<RclcppImpl, AgnocastImpl> impl_;
};
} // namespace nebula::agnocast_wrapper
#else // !USE_AGNOCAST_ENABLED
namespace nebula::agnocast_wrapper
{
// Agnocast-disabled build: a thin composition wrapper over ::rclcpp::AsyncParametersClient rather
// than a derived class, so the full upstream API cannot leak into the =0 build and let =0-only code
// compile that breaks under =1. Signatures and semantics match the agnocast-enabled build above,
// which carries the documentation.
class AsyncParametersClient
{
public:
explicit AsyncParametersClient(
nebula::agnocast_wrapper::Node * node, const std::string & remote_node_name = "",
const rclcpp::QoS & qos = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: impl_(
node->get_rclcpp_node().get(), remote_node_name,
detail::to_rclcpp_parameters_qos(detail::checked_parameters_qos(qos)), std::move(group))
{
}
std::shared_future<std::vector<rclcpp::Parameter>> get_parameters(
const std::vector<std::string> & names,
std::function<void(std::shared_future<std::vector<rclcpp::Parameter>>)> callback = nullptr)
{
return impl_.get_parameters(names, std::move(callback));
}
template <typename RepT = int64_t, typename RatioT = std::milli>
bool wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return impl_.wait_for_service(timeout);
}
bool service_is_ready() const { return impl_.service_is_ready(); }
AsyncParametersClient(const AsyncParametersClient &) = delete;
AsyncParametersClient & operator=(const AsyncParametersClient &) = delete;
AsyncParametersClient(AsyncParametersClient &&) = delete;
AsyncParametersClient & operator=(AsyncParametersClient &&) = delete;
private:
::rclcpp::AsyncParametersClient impl_;
};
} // namespace nebula::agnocast_wrapper
#endif