diff --git a/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.hpp b/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.hpp new file mode 100644 index 0000000000..ced778f28e --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.hpp @@ -0,0 +1,85 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_CLIENT_IMPL_HPP +#define IOX_POSH_POPO_CLIENT_IMPL_HPP + +#include "iceoryx_posh/capro/service_description.hpp" +#include "iceoryx_posh/internal/popo/base_client.hpp" +#include "iceoryx_posh/internal/popo/request_deleter.hpp" +#include "iceoryx_posh/internal/popo/response_deleter.hpp" +#include "iceoryx_posh/internal/popo/rpc_interface.hpp" +#include "iceoryx_posh/internal/popo/typed_port_api_trait.hpp" +#include "iceoryx_posh/popo/client_options.hpp" +#include "iceoryx_posh/popo/request.hpp" +#include "iceoryx_posh/popo/response.hpp" +#include "iceoryx_posh/popo/trigger_handle.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" + +namespace iox +{ +namespace popo +{ +template > +class ClientImpl : public BaseClientT, public RpcInterface> +{ + using RequestTypeAssert = typename TypedPortApiTrait::Assert; + using ResponseTypeAssert = typename TypedPortApiTrait::Assert; + + public: + /// @brief Constructor for a client + /// @param[in] service is the ServiceDescription for the new client + /// @param[in] clientOptions like the queue capacity and queue full policy by a client + explicit ClientImpl(const capro::ServiceDescription& service, const ClientOptions& clientOptions = {}) noexcept; + ClientImpl(const ClientImpl&) = delete; + ClientImpl(ClientImpl&&) = delete; + ClientImpl& operator=(const ClientImpl&) = delete; + ClientImpl& operator=(ClientImpl&&) = delete; + + /// @brief Get a Request from loaned shared memory and construct the data with the given arguments. + /// @param[in] args Arguments used to construct the data. + /// @return An instance of the Request that resides in shared memory or an error if unable to allocate memory to + /// loan. + /// @details The loaned Request is automatically released when it goes out of scope. + template + cxx::expected, AllocationError> loan(Args&&... args) noexcept; + + /// @brief Sends the given Request and then releases its loan. + /// @param request to send. + void send(Request&& request) noexcept override; + + /// @brief Take the Response from the top of the receive queue. + /// @return Either a Response or a ChunkReceiveResult. + /// @details The Response takes care of the cleanup. Don't store the raw pointer to the content of the Response, but + /// always the whole Response. + cxx::expected, ChunkReceiveResult> take() noexcept; + + private: + using BaseClientT::port; + + cxx::expected, AllocationError> loanUninitialized() noexcept; + + using RequestSampleDeleter = RequestDeleter; + RequestSampleDeleter m_requestDeleter{port()}; + using ResponseSampleDeleter = ResponseDeleter; + ResponseSampleDeleter m_responseDeleter{port()}; +}; +} // namespace popo +} // namespace iox + +#include "iceoryx_posh/internal/popo/client_impl.inl" + +#endif // IOX_POSH_POPO_CLIENT_IMPL_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.inl b/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.inl new file mode 100644 index 0000000000..81c972f7f2 --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/internal/popo/client_impl.inl @@ -0,0 +1,81 @@ +// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_CLIENT_IMPL_INL +#define IOX_POSH_POPO_CLIENT_IMPL_INL + +#include "iceoryx_posh/internal/popo/client_impl.hpp" + +namespace iox +{ +namespace popo +{ +template +ClientImpl::ClientImpl(const capro::ServiceDescription& service, + const ClientOptions& clientOptions) noexcept + : BaseClientT(service, clientOptions) +{ +} + +template +cxx::expected, AllocationError> ClientImpl::loanUninitialized() noexcept +{ + auto result = port().allocateRequest(sizeof(Req), alignof(Req)); + if (result.has_error()) + { + return cxx::error(result.get_error()); + } + auto requestHeader = result.value(); + auto payload = mepoo::ChunkHeader::fromUserHeader(requestHeader)->userPayload(); + auto request = cxx::unique_ptr(reinterpret_cast(payload), m_requestDeleter); + return cxx::success>(Request{std::move(request), *this}); +} + +template +template +cxx::expected, AllocationError> ClientImpl::loan(Args&&... args) noexcept +{ + return std::move( + loanUninitialized().and_then([&](auto& request) { new (request.get()) Req(std::forward(args)...); })); +} + +template +void ClientImpl::send(Request&& request) noexcept +{ + // take the ownership of the chunk from the Request to transfer it to `sendRequest` + auto payload = request.release(); + auto* requestHeader = static_cast(mepoo::ChunkHeader::fromUserPayload(payload)->userHeader()); + port().sendRequest(requestHeader); +} + +template +cxx::expected, ChunkReceiveResult> ClientImpl::take() noexcept +{ + auto result = port().getResponse(); + if (result.has_error()) + { + return cxx::error(result.get_error()); + } + auto responseHeader = result.value(); + auto payload = mepoo::ChunkHeader::fromUserHeader(responseHeader)->userPayload(); + auto response = cxx::unique_ptr(static_cast(payload), m_responseDeleter); + return cxx::success>(Response{std::move(response)}); +} + +} // namespace popo +} // namespace iox + +#endif // IOX_POSH_POPO_CLIENT_IMPL_INL diff --git a/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.hpp b/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.hpp new file mode 100644 index 0000000000..5f5d047b74 --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.hpp @@ -0,0 +1,86 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_SERVER_IMPL_HPP +#define IOX_POSH_POPO_SERVER_IMPL_HPP + +#include "iceoryx_posh/capro/service_description.hpp" +#include "iceoryx_posh/internal/popo/base_server.hpp" +#include "iceoryx_posh/internal/popo/request_deleter.hpp" +#include "iceoryx_posh/internal/popo/response_deleter.hpp" +#include "iceoryx_posh/internal/popo/rpc_interface.hpp" +#include "iceoryx_posh/internal/popo/typed_port_api_trait.hpp" +#include "iceoryx_posh/popo/request.hpp" +#include "iceoryx_posh/popo/response.hpp" +#include "iceoryx_posh/popo/server_options.hpp" +#include "iceoryx_posh/popo/trigger_handle.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" + +namespace iox +{ +namespace popo +{ +template > +class ServerImpl : public BaseServerT, public RpcInterface> +{ + using RequestTypeAssert = typename TypedPortApiTrait::Assert; + using ResponseTypeAssert = typename TypedPortApiTrait::Assert; + + public: + /// @brief Constructor for a sserver + /// @param[in] service is the ServiceDescription for the new server + /// @param[in] serverOptions like the queue capacity and queue full policy by a server + explicit ServerImpl(const capro::ServiceDescription& service, const ServerOptions& serverOptions = {}) noexcept; + ServerImpl(const ServerImpl&) = delete; + ServerImpl(ServerImpl&&) = delete; + ServerImpl& operator=(const ServerImpl&) = delete; + ServerImpl& operator=(ServerImpl&&) = delete; + + /// @brief Take the Request from the top of the receive queue. + /// @return Either a Request or a ServerRequestResult. + /// @details The Request takes care of the cleanup. Don't store the raw pointer to the content of the Request, but + /// always the whole Request. + cxx::expected, ServerRequestResult> take() noexcept; + + /// @brief Get a Response from loaned shared memory and construct the data with the given arguments. + /// @param[in] request The request to which the Response belongs to, to determine where to send the response + /// @param[in] args Arguments used to construct the data. + /// @return An instance of the Response that resides in shared memory or an error if unable to allocate memory to + /// loan. + /// @details The loaned Response is automatically released when it goes out of scope. + template + cxx::expected, AllocationError> loan(const Request& request, Args&&... args) noexcept; + + /// @brief Sends the given Response and then releases its loan. + /// @param response to send. + void send(Response&& response) noexcept override; + + private: + using BaseServerT::port; + + cxx::expected, AllocationError> loanUninitialized(const Request& request) noexcept; + + using RequestSampleDeleter = RequestDeleter; + RequestSampleDeleter m_requestDeleter{port()}; + using ResponseSampleDeleter = ResponseDeleter; + ResponseSampleDeleter m_responseDeleter{port()}; +}; +} // namespace popo +} // namespace iox + +#include "iceoryx_posh/internal/popo/server_impl.inl" + +#endif // IOX_POSH_POPO_SERVER_IMPL_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.inl b/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.inl new file mode 100644 index 0000000000..742f9afe26 --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/internal/popo/server_impl.inl @@ -0,0 +1,84 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_SERVER_IMPL_INL +#define IOX_POSH_POPO_SERVER_IMPL_INL + +#include "iceoryx_posh/internal/popo/server_impl.hpp" + +namespace iox +{ +namespace popo +{ +template +inline ServerImpl::ServerImpl(const capro::ServiceDescription& service, + const ServerOptions& serverOptions) noexcept + : BaseServerT(service, serverOptions) +{ +} + +template +cxx::expected, ServerRequestResult> ServerImpl::take() noexcept +{ + auto result = port().getRequest(); + if (result.has_error()) + { + return cxx::error(result.get_error()); + } + auto requestHeader = result.value(); + auto payload = mepoo::ChunkHeader::fromUserHeader(requestHeader)->userPayload(); + auto request = cxx::unique_ptr(static_cast(payload), m_requestDeleter); + return cxx::success>(Request{std::move(request)}); +} + +template +cxx::expected, AllocationError> +ServerImpl::loanUninitialized(const Request& request) noexcept +{ + const auto* requestHeader = &request.getRequestHeader(); + auto result = port().allocateResponse(requestHeader, sizeof(Res), alignof(Res)); + if (result.has_error()) + { + return cxx::error(result.get_error()); + } + auto responseHeader = result.value(); + auto payload = mepoo::ChunkHeader::fromUserHeader(responseHeader)->userPayload(); + auto response = cxx::unique_ptr(reinterpret_cast(payload), m_responseDeleter); + return cxx::success>(Response{std::move(response), *this}); +} + +template +template +cxx::expected, AllocationError> ServerImpl::loan(const Request& request, + Args&&... args) noexcept +{ + return std::move(loanUninitialized(request).and_then( + [&](auto& response) { new (response.get()) Res(std::forward(args)...); })); +} + +template +void ServerImpl::send(Response&& response) noexcept +{ + // take the ownership of the chunk from the Response to transfer it to `sendResponse` + auto payload = response.release(); + auto* responseHeader = static_cast(mepoo::ChunkHeader::fromUserPayload(payload)->userHeader()); + port().sendResponse(responseHeader); +} + +} // namespace popo +} // namespace iox + +#endif // IOX_POSH_POPO_SERVER_IMPL_INL diff --git a/iceoryx_posh/include/iceoryx_posh/internal/popo/typed_port_api_trait.hpp b/iceoryx_posh/include/iceoryx_posh/internal/popo/typed_port_api_trait.hpp new file mode 100644 index 0000000000..f63f25c2d0 --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/internal/popo/typed_port_api_trait.hpp @@ -0,0 +1,50 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_TYPED_PORT_API_TRAIT_HPP +#define IOX_POSH_POPO_TYPED_PORT_API_TRAIT_HPP + +#include + +namespace iox +{ +namespace popo +{ +/// @brief This type trait ensures that the template parameter for Publisher, Subscriber, Client and Server fulfill +/// specific constrains. +/// @code +/// template +/// class Producer +/// { +/// using DataTypeAssert = typename TypedPortApiTrait::Assert; +/// public: +/// // ... +/// } +/// @endcode +/// @note `typename TypedPortApiTrait::Assert` has to be used otherwise the compiler ignores the static_assert's +template +struct TypedPortApiTrait +{ + static_assert(!std::is_void::value, "Must not be void. Use the untyped API for void types"); + static_assert(!std::is_const::value, "Must not be const"); + static_assert(!std::is_reference::value, "Must not be a reference"); + static_assert(!std::is_pointer::value, "Must not be a pointer"); + using Assert = void; +}; +} // namespace popo +} // namespace iox + +#endif // IOX_POSH_POPO_TYPED_PORT_API_TRAIT_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/popo/client.hpp b/iceoryx_posh/include/iceoryx_posh/popo/client.hpp new file mode 100644 index 0000000000..ae75d63aaa --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/popo/client.hpp @@ -0,0 +1,38 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_CLIENT_HPP +#define IOX_POSH_POPO_CLIENT_HPP + +#include "iceoryx_posh/internal/popo/client_impl.hpp" + +namespace iox +{ +namespace popo +{ +/// @brief The Client class for the request-response messaging pattern in iceoryx. +/// @param[in] Req type of request data +/// @param[in] Res type of response data +template +class Client : public ClientImpl +{ + public: + using ClientImpl::ClientImpl; +}; +} // namespace popo +} // namespace iox + +#endif // IOX_POSH_POPO_CLIENT_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/popo/publisher.hpp b/iceoryx_posh/include/iceoryx_posh/popo/publisher.hpp index 61078c2e8f..68ce7c664d 100644 --- a/iceoryx_posh/include/iceoryx_posh/popo/publisher.hpp +++ b/iceoryx_posh/include/iceoryx_posh/popo/publisher.hpp @@ -19,6 +19,7 @@ #define IOX_POSH_POPO_TYPED_PUBLISHER_HPP #include "iceoryx_hoofs/cxx/type_traits.hpp" +#include "iceoryx_posh/internal/popo/typed_port_api_trait.hpp" #include "iceoryx_posh/popo/base_publisher.hpp" #include "iceoryx_posh/popo/sample.hpp" @@ -45,16 +46,8 @@ class PublisherInterface template > class PublisherImpl : public BasePublisher_t, private PublisherInterface { - static_assert(!std::is_void::value, "The type `T` must not be void. Use the UntypedPublisher for void types."); - static_assert(!std::is_void::value, "The user-header `H` must not be void."); - - static_assert(!std::is_const::value, "The type `T` must not be const."); - static_assert(!std::is_reference::value, "The type `T` must not be a reference."); - static_assert(!std::is_pointer::value, "The type `T` must not be a pointer."); - - static_assert(!std::is_const::value, "The user-header `H` must not be const."); - static_assert(!std::is_reference::value, "The user-header `H` must not be a reference."); - static_assert(!std::is_pointer::value, "The user-header must `H` not be a pointer."); + using DataTypeAssert = typename TypedPortApiTrait::Assert; + using HeaderTypeAssert = typename TypedPortApiTrait::Assert; public: PublisherImpl(const capro::ServiceDescription& service, diff --git a/iceoryx_posh/include/iceoryx_posh/popo/server.hpp b/iceoryx_posh/include/iceoryx_posh/popo/server.hpp new file mode 100644 index 0000000000..5a45f0ee86 --- /dev/null +++ b/iceoryx_posh/include/iceoryx_posh/popo/server.hpp @@ -0,0 +1,38 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_POSH_POPO_SERVER_HPP +#define IOX_POSH_POPO_SERVER_HPP + +#include "iceoryx_posh/internal/popo/server_impl.hpp" + +namespace iox +{ +namespace popo +{ +/// @brief The Server class for the request-response messaging pattern in iceoryx. +/// @param[in] Req type of request data +/// @param[in] Res type of response data +template +class Server : public ServerImpl +{ + public: + using ServerImpl::ServerImpl; +}; +} // namespace popo +} // namespace iox + +#endif // IOX_POSH_POPO_SERVER_HPP diff --git a/iceoryx_posh/include/iceoryx_posh/popo/subscriber.hpp b/iceoryx_posh/include/iceoryx_posh/popo/subscriber.hpp index f4ce2613ad..dd34c49d8f 100644 --- a/iceoryx_posh/include/iceoryx_posh/popo/subscriber.hpp +++ b/iceoryx_posh/include/iceoryx_posh/popo/subscriber.hpp @@ -19,6 +19,7 @@ #define IOX_POSH_POPO_TYPED_SUBSCRIBER_HPP #include "iceoryx_posh/internal/popo/sample_deleter.hpp" +#include "iceoryx_posh/internal/popo/typed_port_api_trait.hpp" #include "iceoryx_posh/popo/base_subscriber.hpp" namespace iox @@ -29,7 +30,9 @@ template ; - static_assert(!std::is_void::value, "Type must not be void. Use the UntypedSubscriber for void types."); + + using DataTypeAssert = typename TypedPortApiTrait::Assert; + using HeaderTypeAssert = typename TypedPortApiTrait::Assert; public: SubscriberImpl(const capro::ServiceDescription& service,